Secrets for utrulling: OIDC-føderasjon
fremforge ønsker ikke å holde på produksjons-secretsene dine. Langlivet legitimasjon for utrulling (AWS_ACCESS_KEY_ID, AZURE_CLIENT_SECRET, GCP_SA_KEY, …) som er lagret i CI-systemets secret-lager, er et evig rotasjonsarbeid og en evig skadeflate ved et innbrudd. Den moderne formen er OIDC-føderasjon: workflowen din ber CI-serveren om et kortlivet identitetstoken, skyens IAM verifiserer tokenet og gir tilbake kortlivet legitimasjon. fremforge leverer dette fra ende til ende.
Slik fungerer det
Hver CI-jobb som kjører på fremforge, får et nyutstedt JSON Web Token signert av fremforges OIDC-utsteder for runnere på https://frem.sh/_app/runner/oidc. Tokenet har claims som beskriver jobbens kontekst: repository, ref, workflow og eventuelt miljø, og tillitspolicyen i skyens IAM avgjør ut fra disse claimene om legitimasjon skal gis.
sequenceDiagram
autonumber
actor User
participant FF as fremforge<br/>runner-OIDC issuer
participant Pod as runner VM
participant Cloud as Your cloud's<br/>IAM • STS / WIF / …
User->>FF: git push
FF->>Pod: dispatch job — mint OIDC JWT
Pod->>Cloud: "Here's my JWT, give me credentials"
Cloud->>Cloud: Verify JWT against fremforge JWKS<br/>+ check trust policy claims
Cloud->>Pod: 1h credentials
Pod->>Cloud: deploy / read / write
Claims som tillitspolicyen i skyen kan matche på:
| Claim | Eksempel | Hva den identifiserer |
|---|---|---|
iss | https://frem.sh/_app/runner/oidc | fremforge selv |
aud | sts.amazonaws.com | hvilken sky du autentiserer mot |
sub | repo:my-org/my-repo:environment:production (når environment: er deklarert)repo:my-org/my-repo:ref:refs/heads/main (uten miljø) | hvilken workflow-kjøring |
repository | my-org/my-repo | navnet på repositoryet |
repository_owner | my-org | organisasjonens slug |
ref | refs/heads/main | Git-ref |
environment | production | miljønavnet workflowen deklarerer |
actor | alice | Forgejo-brukernavnet som startet kjøringen |
Disse følger formen på claimene i GitHub Actions, så eksisterende tillitspolicyer og actionene actions/configure-aws-credentials / azure/login / google-github-actions/auth fungerer uten endringer.
Discovery-URL
Pek skyen din mot:
- Utsteder-URL:
https://frem.sh/_app/runner/oidc - JWKS-URL:
https://frem.sh/_app/runner/oidc/.well-known/jwks.json - Discovery-dokument:
https://frem.sh/_app/runner/oidc/.well-known/openid-configuration
Alle tre kan leses anonymt.
Mønstre for workflower
Deklarere et miljø
jobs:
deploy:
runs-on: fremforge-runner
environment: production
permissions:
id-token: write # required to mint the OIDC JWT
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/fremforge-deploy-prod
aws-region: eu-central-1
- run: aws s3 sync ./build s3://my-prod-bucket/environment: production endrer OIDC-claimen sub til repo:my-org/my-repo:environment:production, slik at tillitspolicyen din kan gi tilgang bare til jobber som deklarerer production.
Uten miljø
Når du ikke deklarerer environment:, faller sub tilbake til repo:<owner>/<repo>:ref:<ref>. Tillitspolicyer som matcher på ref, fungerer på samme måte som på GitHub. Miljøsperren på fremforge-siden gjelder ikke (den sperrer bare workflower som deklarerer et miljø), så tillitspolicyen i skyen er ditt eneste forsvar.
Eksempler på tillitspolicyer
AWS
IAM-tillitspolicy for en OIDC-føderert rolle:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/frem.sh/_app/runner/oidc"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"frem.sh/_app/runner/oidc:aud": "sts.amazonaws.com"
},
"StringLike": {
"frem.sh/_app/runner/oidc:sub": "repo:my-org/my-repo:environment:production"
}
}
}]
}Engangsoppsett: registrer fremforge som OIDC-leverandør:
aws iam create-open-id-connect-provider \
--url https://frem.sh/_app/runner/oidc \
--client-id-list sts.amazonaws.com \
--thumbprint-list $(curl -s https://frem.sh/_app/runner/oidc/.well-known/jwks.json | jq -r '.keys[0].x5t')Azure (Workload Identity Federation)
Registrer den fødererte legitimasjonen på en App Registration i Entra ID:
az ad app federated-credential create \
--id $APP_OBJECT_ID \
--parameters '{
"name": "fremforge-prod-deploy",
"issuer": "https://frem.sh/_app/runner/oidc",
"subject": "repo:my-org/my-repo:environment:production",
"audiences": ["api://AzureADTokenExchange"]
}'Workflow:
- uses: azure/login@v2
with:
client-id: ${{ vars.AZURE_CLIENT_ID }}
tenant-id: ${{ vars.AZURE_TENANT_ID }}
subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}GCP (Workload Identity Federation)
gcloud iam workload-identity-pools providers create-oidc fremforge-provider \
--workload-identity-pool=fremforge-pool \
--issuer-uri="https://frem.sh/_app/runner/oidc" \
--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository,attribute.environment=assertion.environment" \
--attribute-condition="attribute.environment == 'production'"Workflow:
- uses: google-github-actions/auth@v2
with:
workload_identity_provider: projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/fremforge-pool/providers/fremforge-provider
service_account: deploy@my-project.iam.gserviceaccount.comT Cloud Public (OTC IAM Identity Provider)
T Cloud Public bruker IAM Identity Providers og tokenutveksling:
- Identity Provider i OTC Console → IAM → Identity Providers → Create:
- Name:
fremforge-runner-oidc - Protocol:
OpenID Connect - Issuer URL:
https://frem.sh/_app/runner/oidc - JWKS URL:
https://frem.sh/_app/runner/oidc/.well-known/jwks.json - Client ID:
iam.eu-de.otc.t-systems.com(eller STS-audiencen til prosjektet ditt)
- Name:
- Mapping rules, som oversetter claims til en føderert bruker. Eksempel som mapper subjektet
repo:my-org/my-repo:environment:productiontil OTC-gruppendeploy-prod:
[
{
"local": [
{ "user": { "name": "{0}" } },
{ "group": { "name": "deploy-prod" } }
],
"remote": [
{ "type": "sub" },
{ "type": "environment", "any_one_of": ["production"] }
]
}
]- Workflow: bytt JWT-en mot et OTC-token via IAM-endepunktet for tokenutveksling, og bruk deretter den returnerte
X-Subject-Tokentil alle kall mot OTC-API-et.
Styre hvilke refs som kan rulle ut hvor
OIDC-føderasjon fjerner behovet for å LAGRE langlivede secrets, men du må fortsatt bestemme hvilke brancher som kan rulle ut til hvilket miljø. En workflow på en feature-branch KAN utstede en JWT som hevder environment: production; det er sperren som hindrer at JWT-en blir godtatt.
fremforge tilbyr to sperrer, og du bør bruke begge som forsvar i dybden.
Sperre 1: tillitspolicy i skyen (alltid påkrevd)
Tillitspolicyen i skyens IAM er den endelige autoriteten. Lås claimen sub til formen repository+miljø, OG lås claimen ref til den eller de branchene miljøet har lov til å rulle ut fra. Eksempel for AWS:
{
"Condition": {
"StringEquals": {
"frem.sh/_app/runner/oidc:sub": "repo:my-org/my-repo:environment:production"
},
"StringLike": {
"frem.sh/_app/runner/oidc:ref": "refs/heads/main"
}
}
}En feature-branch KAN utstede JWT-en, men AWS nekter å utstede legitimasjon fordi ref er refs/heads/feature/foo i stedet for refs/heads/main. Dette er grunnmønsteret GitHub anbefaler, og det fungerer fra første dag.
Sperre 2: branch-mønstre for utrulling per miljø på fremforge-siden (anbefalt)
Under Organisasjonsadministrasjon → Miljøer (frem.sh/<org>/_admin/environments) konfigurerer du hvert miljø på GitHub-måten. Hvert miljø har tre seksjoner:
Brancher og tagger for utrulling: glob-mønstre som matches mot Git-refen som utløste kjøringen. Eksempler (får automatisk prefikset refs/heads/ når du bruker kortform for brancher):
| Navn | Mønstre | Effekt |
|---|---|---|
production | main | bare main-branchen |
staging | maindeveloprelease/* | main + develop + release/*-brancher |
pr-preview | * | hvilken som helst branch (sperren i skyen er den reelle autoriteten) |
release | refs/tags/v[0-9]+.* | bare versjons-tagger (eksplisitt prefiks refs/tags/) |
Workflower som deklarerer environment: production, avvises ved utsending når refen som utløste dem, ikke matcher. Workflower UTEN en environment:-deklarasjon kjører uten begrensning, så vanlig CI på feature-brancher fortsetter å fungere.
Miljø-secrets: krypterte, avgrenset til miljøet og injisert som ${{ secrets.NAME }} i workflowen OG som vanlige miljøvariabler når workflowens environment: matcher. Dekker secrets utenfor skyens IAM (API-nøkler hos tredjeparter, signeringsnøkler, webhook-secrets) som OIDC-føderasjon ikke løser.
Miljøvariabler: verdier som ikke er hemmelige, avgrenset til miljøet. Samme injeksjonsmodell.
Hva med godkjenningssperrer?
Environments i GitHub Actions har funksjonen «Required reviewers»: en jobb settes på pause etter merge til N personer klikker Approve i Actions-grensesnittet. fremforge leverer bevisst ikke dette, fordi Forgejo allerede har en sterkere sperre på samme sted i tidslinjen: branchbeskyttelse på main med CODEOWNERS for .forgejo/workflows/* krever gjennomgang av pull requesten før en workflow som kan rulle ut, kommer inn. I 99 % av tilfellene (1 pull request = 1 utrulling) ER gjennomgangen av pull requesten i Forgejo godkjenningen av utrullingen. Kunder som trenger GitHub-tilfellet (1 pull request kan gi N uavhengige utrullinger med egne godkjennere per utrulling), kan opprette en issue, så prioriterer vi godkjennere ved utrulling (planlagt) ut fra faktisk etterspørsel.
Sperren på fremforge-siden hindrer at JWT-en i det hele tatt blir utstedt. Sperren i skyen hindrer at en utstedt JWT blir godtatt. Kombiner begge: selv om en fremtidig feil i fremforge skulle slippe gjennom en avvist utsending, nekter skyens IAM fortsatt å utstede legitimasjon. Selv om tillitspolicyen i en kundes sky har en skrivefeil og godtar et bredere ref-mønster enn tiltenkt, har fremforge fortsatt nektet å utstede JWT-en.
Gradvis innføring
Når du deklarerer environment: x i en workflow, men ennå ikke har konfigurert en environments-rad for x, tillater fremforge utsendingen i stedet for å avvise den. Dette er bevisst, slik at en ny kundes workflower ikke brekker i det øyeblikket de deklarerer et miljø; tillitspolicyen i skyen er sikkerhetsnettet til du legger til raden på fremforge-siden. Når en rad finnes, håndheves sperren.
Låst modus: bare beskyttede brancher
For miljøer med høye sikkerhetskrav der du vil forby CI-kjøring på ubeskyttede refs HELT (ikke bare sperre legitimasjon for utrulling), slår du på Organisasjonsadministrasjon → Miljøer → Låsing for hele organisasjonen → Kjør workflower bare på beskyttede brancher:
Kjør workflower bare på beskyttede brancher
Når den er slått på, nekter plattformen å sende ut ENHVER workflow der branchen som utløste den, IKKE står i repositoryets liste over beskyttede brancher (konfigurert via Forgejos egen Innstillinger → Brancher → Legg til ny regel). Dette gjelder også vanlig CI (tester, lint): ingenting kjører på ubeskyttede brancher. Nyttig i regulerte miljøer der du vil ha null kodekjøring utenfor gjennomgåtte refs; ikke anbefalt for vanlig utviklingsflyt, fordi det ødelegger testing på feature-brancher.
Slår du dette på, beskytter du typisk mønstrene main, develop og release/* i Forgejo, slik at de vanlige utviklingsbranchene dine fortsatt kan kjøre CI.
Anbefalt oppsett
For typiske SaaS- og produktteam:
- Ikke slå på utrullingssperren for bare beskyttede brancher; la vanlig CI kjøre på feature-brancher.
- Konfigurer miljøer under Organisasjonsadministrasjon → Miljøer med passende mønstre under Brancher og tagger for utrulling for hvert (production, staging osv.).
- Konfigurer tillitspolicyer i skyen med både
sub(låst til miljø) OGref(låst til branch) som betingelser. - Branchbeskytt
maini Forgejo med CODEOWNERS-dekning for.forgejo/workflows/*, slik at endringer i workflower krever gjennomgang.
For regulerte eller låste miljøer (bank, forsvar, helse):
- Slå på utrullingssperren for bare beskyttede brancher.
- Konfigurer miljøer for detaljert sperring per miljø i tillegg.
- Samme oppsett av tillitspolicyer i skyen som over.
Denne kombinasjonen tilsvarer modellen for utrullingssperrer som GitHub Enterprise og AWS anbefaler (påkrevde miljøer ved utrulling + bare branchbeskyttede refs), pluss den valgfrie låsebryteren for regulerte kunder.
Sammenligning: hva fremforge lagrer kontra skyen din
| Langlivede secrets | OIDC-føderasjon (denne siden) | |
|---|---|---|
| Hvor legitimasjonen for utrulling ligger | Organisasjonsadministrasjon → Secrets eller Repository → Innstillinger → Actions → Secrets i fremforge | Skyens IAM. fremforge ser den aldri. |
| Levetid for legitimasjonen | Til du roterer | 1 time (kan konfigureres per tillitspolicy) |
| Hvis det brytes inn i fremforge | Angriperen har AWS-nøklene dine | Angriperen kan utstede OIDC-JWT-er, men tillitspolicyen i skyen begrenser hva disse JWT-ene kan gjøre (per miljø, per repository, per ref) |
| Rotasjonsarbeid | Kvartalsvis per secret per sky | Ingen, nøklene roteres for hver jobb |
| Revisjonsspor | Manuelt: hvem eksporterte secreten når | Hver OIDC-utstedelse står i audit_events + skyens CloudTrail/Activity Log |
Begrensninger
environment:i objektform (medname:+url:) støttes via navnet;url:tolkes, men vises foreløpig ikke som en claim.- Miljønavn fra matrise-utvidelse (
environment: ${{ matrix.target }}) løses ikke opp når OIDC-tokenet utstedes, og fører til at ingenenvironment-claim sendes. Bruk en hardkodetenvironment:per matrisejobb hvis du trenger tillitspolicyer basert på miljø-claimen. - Sperrer med påkrevde godkjennere per miljø (som funksjonen «wait for approval» i GitHub Environments) er registrert som oppfølging i fase 2; dagens håndheving er binær (beskyttet branch ja/nei).
Se også
- Integritet i revisjonskjeden: hver OIDC-utstedelse sender en revisjonshendelse inn i hash-kjeden per kunde
- Modellen for hostede runnere: hva som isolerer én kundes runner fra en annens