Najnebezpečnejší riadok v každom pipeline, ktorý som za tie roky videl, je AZURE_CLIENT_SECRET uložený ako pipeline variable. Funguje to. Deploy prebehne. A presne v tej chvíli máte v systéme dlhodobý prihlasovací údaj, ktorý nikto nerotuje, leží v logoch, v env, v pamäti runnera a v hlave každého, kto si ho raz skopíroval do lokálneho .env.
OIDC Workload Identity Federation tento problém nerieši lepším skladovaním tajomstva. Rieši ho tak, že tajomstvo úplne odstráni.
Prečo sú dlhodobé kľúče záväzok
Service principal secret alebo access key má jednu vlastnosť, ktorá ho robí nebezpečným: žije dlho a putuje. Vygenerujete ho raz, nastaví sa expirácia na rok (alebo dva, buďme úprimní), a odvtedy je to statický reťazec, ktorý dáva plný prístup do cloudu komukoľvek, kto ho má.
Rotácia je manuálna a všetci ju nenávidia. Audit je nemožný — keď secret unikne, neviete to, kým niekto neurobí škodu. A radius škody je obrovský, lebo ten istý kľúč zvyčajne používa dev aj prod pipeline.
Ako federácia naozaj funguje
Princíp je výmena tokenov založená na dôvere medzi dvoma identity providermi. Žiadne tajomstvo neprechádza cez pipeline.
- Pipeline (GitHub Actions, Azure DevOps) si od svojho vlastného OIDC providera vyžiada krátkodobý ID token — podpísaný JWT.
- Tento JWT obsahuje claimy, ktoré popisujú, kto a odkiaľ o prístup žiada:
iss(issuer — kto token vydal),sub(subject — repo, branch, tag alebo environment) aaud(audience — pre koho je token určený). - Pipeline pošle tento JWT cloudovému IdP (Microsoft Entra ID, AWS STS).
- Cloud overí podpis tokenu cez verejné kľúče issuera, skontroluje, či
iss+sub+audpresne sedia s vopred nakonfigurovanou dôverou, a ak áno, vymení JWT za krátkodobý access token.
Ten access token žije minúty, nie roky. Po skončení joby je bezcenný. Niet čo rotovať, niet čo uniknúť.
GitHub Actions → Azure
Na strane GitHubu potrebujete jednu vec, ktorú ľudia stále zabúdajú — povolenie pre job vyžiadať si OIDC token:
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: azure/login@v2
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ vars.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
Žiadny secret. Len IDčka, ktoré nie sú citlivé.
Na strane Azure vytvoríte na app registration (alebo managed identity) federated credential. Tam definujete dôveru:
- Issuer:
https://token.actions.githubusercontent.com - Subject: napríklad
repo:moja-org/moja-repo:ref:refs/heads/mainaleborepo:moja-org/moja-repo:environment:production - Audience:
api://AzureADTokenExchange(default)
Entra ID pri requeste overí, že sub v prichádzajúcom JWT presne sedí s tým, čo ste nakonfigurovali. Kombinácia issuer + subject musí byť na app jedinečná.
Azure DevOps a poznámka k AWS
V Azure DevOps to dnes rieši Workload Identity Federation service connection (GA od februára 2024). Namiesto uloženého secretu má service connection vlastnú federovanú dôveru — pipeline si vyžiada token od vstoken.dev.azure.com a vymení ho.
Pri AWS je princíp identický, len pojmy iné. V IAM vytvoríte OIDC identity provider (pre GitHub issuer token.actions.githubusercontent.com, audience sts.amazonaws.com) a IAM rolu s trust policy, ktorá povolí akciu sts:AssumeRoleWithWebIdentity a v podmienke kontroluje sub. Pipeline cez aws-actions/configure-aws-credentials vymení JWT za dočasné STS credentials.
Gotchas, ktoré vás budú stáť večer
Formát subject claimu. Toto je zdroj 80 % problémov. ref:refs/heads/main nie je to isté ako environment:production. Ak vo workflow používate GitHub Environment, subject sa zmení a vaša federated credentials prestane sedieť. Pre každú branch / environment / tag potrebujete buď samostatnú dôveru, alebo flexible federated credentials s wildcardom.
no matching federated identity record found. Klasika. Znamená to jednu z troch vecí: chýba id-token: write v tom konkrétnom jobe, sub nesedí na znak, alebo nesedí aud. Najrýchlejšia diagnostika — nechajte si v pipeline vypísať reálne claimy tokenu a porovnajte ich znak po znaku s konfiguráciou na cloude.
Audience mismatch. Default api://AzureADTokenExchange platí pre public Azure. Pre AWS je to sts.amazonaws.com. Pre suverénne cloudy sú hodnoty iné. Nikdy ich neodhadujte.
TTL. Token žije minúty. Dlhé deployy, ktoré si token vyžiadajú na začiatku a používajú ho po hodine, padnú. Vyžiadajte si ho čo najbližšie k použitiu.
Čo sa zmení v prevádzke
Po prechode na federáciu zmizne rotácia secretov ako disciplína — nie je čo rotovať. Least privilege je konečne reálny, lebo každú dôveru viažete na konkrétne repo, branch a environment, nie na jeden zdieľaný kľúč. A keď niekto forkne repo alebo spustí workflow z nesprávnej branch, dôvera jednoducho nesedí a prístup nedostane.
Najlepší secret je ten, ktorý neexistuje. OIDC federácia je presne to.