Hemligheter för driftsättning: OIDC-federation
fremforge vill inte hålla dina hemligheter för produktion. Långlivade inloggningsuppgifter för driftsättning (AWS_ACCESS_KEY_ID, AZURE_CLIENT_SECRET, GCP_SA_KEY, …) som lagras i CI-systemets hemlighetslager är ett ständigt rotationsarbete och en ständig risk vid intrång. Det moderna upplägget är OIDC-federation: ditt arbetsflöde ber CI-servern om en kortlivad identitetstoken, ditt molns IAM verifierar token och lämnar tillbaka en kortlivad inloggningsuppgift. fremforge levererar detta från början till slut.
Så fungerar det
Varje CI-jobb som körs på fremforge får en nyskapad JSON Web Token signerad av fremforges OIDC-utfärdare för runners på https://frem.sh/_app/runner/oidc. Token innehåller claims som beskriver jobbets sammanhang (repo, ref, arbetsflöde, eventuellt miljö), och förtroendepolicyn i ditt molns IAM avgör utifrån dessa claims om inloggningsuppgifter ska beviljas.
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 ditt molns förtroendepolicy kan matcha på:
| Claim | Exempel | Vad det identifierar |
|---|---|---|
iss | https://frem.sh/_app/runner/oidc | fremforge självt |
aud | sts.amazonaws.com | vilket moln du autentiserar mot |
sub | repo:my-org/my-repo:environment:production (när environment: är deklarerad)repo:my-org/my-repo:ref:refs/heads/main (utan miljö) | vilken körning av arbetsflödet |
repository | my-org/my-repo | repots namn |
repository_owner | my-org | organisationens slug |
ref | refs/heads/main | git-ref |
environment | production | miljönamnet som arbetsflödet deklarerar |
actor | alice | Forgejo-användarnamnet som startade körningen |
De motsvarar strukturen för claims i GitHub Actions, så befintliga förtroendepolicyer och actions som actions/configure-aws-credentials / azure/login / google-github-actions/auth fungerar utan ändringar.
Discovery-URL
Peka ditt moln mot:
- Utfärdar-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
Alla tre kan läsas anonymt.
Mönster för arbetsflöden
Deklarera en 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 ändrar OIDC-claimet sub till repo:my-org/my-repo:environment:production, så att din förtroendepolicy kan ge åtkomst bara till jobb som deklarerar production.
Utan miljö
När du inte deklarerar environment: faller sub tillbaka till repo:<owner>/<repo>:ref:<ref>. Förtroendepolicyer som matchar på ref fungerar på samma sätt som på GitHub. Spärren för miljöer på fremforges sida gäller inte (den spärrar bara arbetsflöden som deklarerar en miljö), så förtroendepolicyn på molnsidan är ditt enda skydd.
Exempel på förtroendepolicyer
AWS
IAM-förtroendepolicy för en OIDC-federerad roll:
{
"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"
}
}
}]
}Engångskonfiguration: registrera fremforge som OIDC-leverantö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)
Registrera den federerade inloggningsuppgiften på en appregistrering 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"]
}'Arbetsflöde:
- 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'"Arbetsflöde:
- 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 använder IAM Identity Providers + tokenutbyte:
- 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 ditt projekts STS-audience)
- Name:
- Mappningsregler, som översätter claims till en federerad användare. Exempel som mappar ett subject
repo:my-org/my-repo:environment:productiontill OTC-gruppendeploy-prod:
[
{
"local": [
{ "user": { "name": "{0}" } },
{ "group": { "name": "deploy-prod" } }
],
"remote": [
{ "type": "sub" },
{ "type": "environment", "any_one_of": ["production"] }
]
}
]- Arbetsflöde: byt JWT:n mot en OTC-token via IAM:s slutpunkt för tokenutbyte, och använd sedan den returnerade
X-Subject-Tokenför alla anrop till OTC:s API.
Styra vilka refs som får driftsätta var
OIDC-federation tar bort behovet av att LAGRA långlivade hemligheter, men du behöver fortfarande bestämma vilka branches som får driftsätta till vilken miljö. Ett arbetsflöde på en feature-branch KAN skapa en JWT som påstår environment: production; spärren är det som hindrar att JWT:n godtas.
fremforge erbjuder två spärrar, och du bör använda båda som skydd i flera lager.
Spärr 1: förtroendepolicy på molnsidan (alltid obligatorisk)
Förtroendepolicyn i ditt molns IAM har sista ordet. Lås claimet sub till strukturen repo+miljö OCH lås claimet ref till den eller de branches som miljön får driftsättas från. Exempel för 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 skapa JWT:n, men AWS vägrar utfärda inloggningsuppgifter eftersom ref är refs/heads/feature/foo i stället för refs/heads/main. Det här är det grundmönster som GitHub rekommenderar och fungerar från första dagen.
Spärr 2: mönster för driftsättningsbranches per miljö på fremforges sida (rekommenderas)
Under Organisationens administration → Miljöer (frem.sh/<org>/_admin/environments) konfigurerar du varje miljö på GitHub-vis. Tre avsnitt per miljö:
Branches och taggar för driftsättning: glob-mönster som matchas mot den git-ref som startade körningen. Exempel (förkortningar för branches får automatiskt prefixet refs/heads/):
| Namn | Mönster | Effekt |
|---|---|---|
production | main | bara main-branchen |
staging | maindeveloprelease/* | branches main + develop + release/* |
pr-preview | * | vilken branch som helst (spärren på molnsidan är den verkliga auktoriteten) |
release | refs/tags/v[0-9]+.* | bara versionstaggar (uttryckligt prefix refs/tags/) |
Arbetsflöden som deklarerar environment: production avvisas vid start när den ref som startade dem inte matchar. Arbetsflöden UTAN deklarationen environment: körs utan begränsning, så vanlig CI på feature-branches fortsätter att fungera.
Miljösecrets: krypterade, avgränsade till miljön och injicerade som ${{ secrets.NAME }} i arbetsflödet OCH som vanliga miljövariabler när arbetsflödets environment: matchar. Täcker de fall av hemligheter som inte rör molnets IAM (API-nycklar från tredje part, signeringsnycklar, webhook-hemligheter) och som OIDC-federation inte löser.
Miljövariabler: värden som inte är hemliga, avgränsade till miljön. Samma injiceringsmodell.
Hur är det med spärrar för godkännande?
Miljöer i GitHub Actions har funktionen “Required reviewers”: ett jobb pausas efter merge tills N personer klickar på Approve i Actions-gränssnittet. fremforge levererar avsiktligt inte detta, eftersom Forgejo redan har en starkare spärr vid samma punkt i tidslinjen: branch-skydd på main med CODEOWNERS för .forgejo/workflows/* kräver granskning av pull requesten innan ett arbetsflöde som kan driftsätta landar. I 99 % av fallen (1 PR = 1 driftsättning) ÄR granskningen av pull requesten i Forgejo godkännandet av driftsättningen. Kunder som behöver GitHubs fall (1 PR kan ge N oberoende driftsättningar med separata godkännare per driftsättning) kan skicka in ett ärende, så prioriterar vi godkännare vid driftsättning (planerat) utifrån faktisk efterfrågan.
Spärren på fremforges sida hindrar att JWT:n skapas över huvud taget. Spärren på molnsidan hindrar att en skapad JWT godtas. Kombinera båda: även om en framtida bugg i fremforge skulle släppa igenom en avvisad start vägrar molnets IAM ändå att utfärda inloggningsuppgifter. Även om en kunds förtroendepolicy i molnet har ett skrivfel och godtar ett bredare ref-mönster än avsett, har fremforge ändå vägrat att skapa JWT:n.
Successiv införing
När du deklarerar environment: x i ett arbetsflöde men ännu inte har konfigurerat en rad i environments för x, tillåter fremforge starten i stället för att avvisa den. Det är avsiktligt, så att en ny kunds arbetsflöden inte går sönder i samma stund som de deklarerar en miljö; förtroendepolicyn på molnsidan är skyddsnätet tills du lägger till raden på fremforges sida. När en rad finns tillämpas spärren.
Låst läge: bara skyddade branches
För miljöer med höga säkerhetskrav där du vill förbjuda CI-körning på oskyddade refs HELT (inte bara spärra inloggningsuppgifter för driftsättning), aktivera Organisationens administration → Miljöer → Organisationsövergripande låsning → Kör bara arbetsflöden på skyddade branches:
Kör bara arbetsflöden på skyddade branches
När det är aktiverat vägrar plattformen starta NÅGOT arbetsflöde vars utlösande branch INTE finns i repots lista över skyddade branches (konfigureras via Forgejos inbyggda Inställningar → Grenar → Lägg till ny regel). Det inkluderar vanlig CI (tester, lint): inget körs på oskyddade branches. Användbart i reglerade miljöer där du inte vill ha någon kodkörning utanför granskade refs; rekommenderas inte för normalt utvecklingsflöde eftersom det bryter testning på feature-branches.
Om du aktiverar detta skyddar du vanligtvis mönstren main, develop och release/* i Forgejo så att dina vanliga utvecklingsbranches fortfarande kan köra CI.
Rekommenderad hållning
För typiska SaaS- och produktteam:
- Aktivera inte driftsättningsspärren för bara skyddade branches, låt vanlig CI köras på feature-branches.
- Konfigurera miljöer under Organisationens administration → Miljöer med lämpliga mönster för branches och taggar för driftsättning för var och en (production, staging osv.).
- Konfigurera förtroendepolicyer i molnet med både villkoret
sub(låst till miljö) OCHref(låst till branch). - Skydda
maini Forgejo med CODEOWNERS för.forgejo/workflows/*så att ändringar i arbetsflöden kräver granskning.
För reglerade miljöer och låsta miljöer (bank, försvar, vård):
- Aktivera driftsättningsspärren för bara skyddade branches.
- Konfigurera miljöer för detaljerad spärr per miljö ovanpå det.
- Samma hållning för förtroendepolicyer på molnsidan som ovan.
Den här kombinationen motsvarar den modell för driftsättningsspärrar som GitHub Enterprise och AWS rekommenderar (krav på miljöer vid driftsättning + bara skyddade branches) plus det valfria låsta läget för reglerade tenants.
Jämförelse: vad fremforge lagrar kontra ditt moln
| Långlivade hemligheter | OIDC-federation (den här sidan) | |
|---|---|---|
| Var inloggningsuppgifterna för driftsättning finns | Inställningar → Secrets i fremforge | I ditt molns IAM. fremforge ser dem aldrig. |
| Inloggningsuppgiftens livslängd | Tills du roterar | 1 timme (kan konfigureras per förtroendepolicy) |
| Om fremforge utsätts för intrång | Angriparen har dina AWS-nycklar | Angriparen kan skapa OIDC-JWT:er, men förtroendepolicyn på molnsidan begränsar vad de kan göra (per miljö, per repo, per ref) |
| Rotationsarbete | Varje kvartal per hemlighet och moln | Inget, nycklarna roteras för varje jobb |
| Granskningsspår | Manuellt: vem som exporterade hemligheten och när | Varje OIDC-utfärdande finns i audit_events + ditt molns CloudTrail/Activity Log |
Begränsningar
environment:i objektform (medname:+url:) stöds via namnet;url:tolkas men exponeras för närvarande inte som ett claim.- Miljönamn som expanderas från en matris (
environment: ${{ matrix.target }}) löses inte upp när OIDC-token skapas, och leder till att inget claimenvironmentskickas. Använd en hårdkodadenvironment:per matrisjobb om du behöver förtroendepolicyer baserade på miljö-claimet. - Spärrar med obligatoriska godkännare per miljö (som funktionen “wait for approval” i GitHub Environments) följs upp som fas 2; dagens tillämpning är binär (skyddad branch ja/nej).
Se även
- Granskningskedjans integritet: varje OIDC-utfärdande genererar en granskningshändelse i hashkedjan per tenant
- Säkerhetsmodell för hostade runners: vad som isolerar en kunds runner från en annans