Gå til hovedinnhold

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å:

ClaimEksempelHva den identifiserer
isshttps://frem.sh/_app/runner/oidcfremforge selv
audsts.amazonaws.comhvilken sky du autentiserer mot
subrepo: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
repositorymy-org/my-reponavnet på repositoryet
repository_ownermy-orgorganisasjonens slug
refrefs/heads/mainGit-ref
environmentproductionmiljønavnet workflowen deklarerer
actoraliceForgejo-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.com

T Cloud Public (OTC IAM Identity Provider)

T Cloud Public bruker IAM Identity Providers og tokenutveksling:

  1. 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)
  2. Mapping rules, som oversetter claims til en føderert bruker. Eksempel som mapper subjektet repo:my-org/my-repo:environment:production til OTC-gruppen deploy-prod:
[
  {
    "local": [
      { "user": { "name": "{0}" } },
      { "group": { "name": "deploy-prod" } }
    ],
    "remote": [
      { "type": "sub" },
      { "type": "environment", "any_one_of": ["production"] }
    ]
  }
]
  1. Workflow: bytt JWT-en mot et OTC-token via IAM-endepunktet for tokenutveksling, og bruk deretter den returnerte X-Subject-Token til 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):

NavnMønstreEffekt
productionmainbare main-branchen
stagingmain
develop
release/*
main + develop + release/*-brancher
pr-preview*hvilken som helst branch (sperren i skyen er den reelle autoriteten)
releaserefs/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:

  1. Ikke slå på utrullingssperren for bare beskyttede brancher; la vanlig CI kjøre på feature-brancher.
  2. Konfigurer miljøer under Organisasjonsadministrasjon → Miljøer med passende mønstre under Brancher og tagger for utrulling for hvert (production, staging osv.).
  3. Konfigurer tillitspolicyer i skyen med både sub (låst til miljø) OG ref (låst til branch) som betingelser.
  4. Branchbeskytt main i Forgejo med CODEOWNERS-dekning for .forgejo/workflows/*, slik at endringer i workflower krever gjennomgang.

For regulerte eller låste miljøer (bank, forsvar, helse):

  1. Slå på utrullingssperren for bare beskyttede brancher.
  2. Konfigurer miljøer for detaljert sperring per miljø i tillegg.
  3. 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 secretsOIDC-føderasjon (denne siden)
Hvor legitimasjonen for utrulling liggerOrganisasjonsadministrasjon → Secrets eller Repository → Innstillinger → Actions → Secrets i fremforgeSkyens IAM. fremforge ser den aldri.
Levetid for legitimasjonenTil du roterer1 time (kan konfigureres per tillitspolicy)
Hvis det brytes inn i fremforgeAngriperen har AWS-nøklene dineAngriperen kan utstede OIDC-JWT-er, men tillitspolicyen i skyen begrenser hva disse JWT-ene kan gjøre (per miljø, per repository, per ref)
RotasjonsarbeidKvartalsvis per secret per skyIngen, nøklene roteres for hver jobb
RevisjonssporManuelt: hvem eksporterte secreten nårHver OIDC-utstedelse står i audit_events + skyens CloudTrail/Activity Log

Begrensninger

  • environment: i objektform (med name: + 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 ingen environment-claim sendes. Bruk en hardkodet environment: 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å