OIDC-tokenfederatie
Elke CI-job van fremforge kan een kortlevend OIDC-token krijgen: een met RS256 ondertekende JWT die wordt uitgegeven door de runner-OIDC-issuer van fremforge. Cloudproviders (T Cloud Public, AWS, Azure, GCP) kun je zo instellen dat ze dit token vertrouwen en het inwisselen voor afgebakende, tijdelijke inloggegevens. Geen deploysleutels opgeslagen als secrets, niets om volgens een schema te roteren.
Overzicht van de claims
De runner-JWT van fremforge bevat de volgende claims:
| Claim | Waarde / formaat | Voorbeeld |
|---|---|---|
iss | https://frem.sh/_app/runner/oidc (één globale issuer voor alle organisaties) | https://frem.sh/_app/runner/oidc |
sub | repo:<org>/<repo>:ref:refs/heads/<branch> | repo:acme/api:ref:refs/heads/main |
aud | Instelbaar; standaard https://frem.sh | https://frem.sh |
repository_owner | Slug van de organisatie; leg voorwaarden in het vertrouwensbeleid vast op deze claim voor isolatie per organisatie onder de gedeelde issuer | acme |
repository | <org>/<repo> | acme/api |
ref | Volledige Git-ref | refs/heads/main |
sha | SHA van de commit | a1b2c3d4... |
environment | Naam van de deployment-omgeving (als de job er een declareert) | production |
job_workflow_ref | Pad en ref van het workflowbestand | acme/api/.forgejo/workflows/deploy.yaml@refs/heads/main |
deployer_group | (Alleen T Cloud Public) Naam van de IAM-groep waaraan de gefedereerde gebruiker wordt gekoppeld, per workload ingesteld door fremforge; zie Vertrouwen via agencies in T Cloud Public | acme-prod-deployers |
De claim sub is in de meeste vertrouwensbeleidsregels van providers het belangrijkste ankerpunt. Hij identificeert de combinatie van organisatie, repository en branch eenduidig. Voor isolatie per organisatie in gedeelde cloudaccounts voeg je een voorwaarde toe die repository_owner (de slug van je organisatie) vastlegt; hetzelfde patroon als bij het vertrouwen van GitHub Actions op token.actions.githubusercontent.com. fremforge gebruikt één globale issuer voor alle organisaties; de isolatie van vertrouwen wordt afgedwongen op het niveau van de claims, niet op dat van de issuer-URL.
Het token ophalen in een workflow
Voeg id-token: write toe aan het permissions-blok van de job. De runner vult dan ACTIONS_ID_TOKEN_REQUEST_TOKEN en ACTIONS_ID_TOKEN_REQUEST_URL in als omgevingsvariabelen, waarmee je de eigenlijke JWT ophaalt:
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: fremforge
steps:
- name: Get OIDC token
run: |
TOKEN=$(curl -sS \
-H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://frem.sh" \
| jq -r .value)
echo "TOKEN=$TOKEN" >> $GITHUB_ENVDe meeste providerspecifieke stappen (AWS, Azure, GCP) halen het token zelf op. Je schrijft het handmatig ophalen hierboven alleen als je de ruwe JWT nodig hebt voor een eigen vertrouwensstroom.
Vertrouwen via agencies in T Cloud Public
Het IAM-federatiemodel van T Cloud Public is afgeleid van OpenStack: je registreert de OIDC-issuer als identity provider, koppelt er een mapping aan die claims uit het ID-token vertaalt naar lokale IAM-groepen, en wisselt daarna het ID-token van de runner bij het OS-FEDERATION-endpoint van OTC in voor een Keystone-token van T Cloud Public dat is beperkt tot de groepen die de mapping koppelde.
fremforge gebruikt groepskoppeling op basis van claims (dezelfde vorm als AWS Identity Center, GCP Workload Identity Federation en Azure Federated Credentials): het ID-token van de runner bevat per workload een claim deployer_group, en je OTC-mapping leest die claim letterlijk. Eén mappingregel dekt je hele vloot: een workload toevoegen raakt je IAM helemaal niet.
Stap 1: maak een OpenID Connect-identity provider aan
Ga in de console van T Cloud Public naar IAM → Identity Providers → Create Identity Provider.
- Type: Virtual user
- Protocol: OpenID Connect
- Access type: Programmatic access (
program)
Stel na het aanmaken de OIDC-instellingen in:
- Identity provider URL (
idp_url):https://frem.sh/_app/runner/oidc(één globale issuer; komt overeen met de claimissin elk runner-ID-token van fremforge). - Client ID (
client_id):https://frem.sh; moet gelijk zijn aan de claimaudin het runner-ID-token. - Signing key (
signing_key): plak de JSON met de publieke JWKS-sleutel. Haal die eenmalig op viahttps://frem.sh/_app/runner/oidc/.well-known/openid-configuration→jwks_urien kopieer de JSON. T Cloud Public haalt de JWKS niet automatisch op, dus plak hem opnieuw wanneer fremforge een rotatie van de JWKS aankondigt (aangekondigd op de trustpagina; rotaties gebeuren hooguit eens per jaar).
Stap 2: voeg de mappingregel op basis van claims toe
Eén regel, schaalbaar voor elk aantal workloads:
[
{
"local": [
{ "user": { "name": "fremforge-{0}-{1}" } },
{ "group": { "name": "{2}" } }
],
"remote": [
{ "type": "repository_owner" },
{ "type": "repository" },
{ "type": "deployer_group" }
]
}
]De vertrouwensopzet:
- De gefedereerde gebruiker wordt lid van de IAM-groep die de claim
deployer_groupin het ID-token noemt ({2}vult de waarde van de claim letterlijk in). - De claim wordt gezet door de runner-OIDC-issuer van fremforge, volgens de koppeling tussen workload en groep die je bij de onboarding afspreekt. Hij kan alleen worden opgegeven voor workloads waarvoor we een regel hebben, en alleen voor de ref die die regel vastlegt (standaard: de main-branch).
- Dezelfde vastgelegde JWT-handtekening, dezelfde filtering op
iss+aud+repository_owner; alleen de beslissing welke workload bij welke groep hoort, is verplaatst van “N mappingregels in OTC” naar “één claim die fremforge uitgeeft”.
Stap 3: maak de IAM-groepen aan die je workloads aannemen
Maak één groep aan per deployerprofiel dat je beschikbaar wilt stellen (bijv. acme-prod-deployers, acme-staging-deployers). Ken elk profiel de project- en EPS-rollen toe die het nodig heeft; die zijn 100% van jou, fremforge raakt je groepsinstellingen nooit aan. De groepsnamen komen overeen met de waarde die fremforge in de claim deployer_group zet, zoals bij de onboarding afgesproken.
Stap 4: laat fremforge weten welke workload welke groep gebruikt
Per e-mail of via een aanroep van de beheer-API: “Repository acme/api, main-branch → groep acme-prod-deployers.” fremforge voegt een regel toe aan zijn tabel runner_deployer_groups. Vanaf de volgende workflowrun bevatten ID-tokens voor die workload deployer_group=acme-prod-deployers, en koppelt je mapping de gefedereerde gebruiker aan die groep.
Een nieuwe repository toevoegen is gewoon nog een e-mail; je OTC-IAM blijft ongewijzigd.
Optioneel: maak een agency aan om aan te nemen
De meeste opstellingen slaan dit over: de groepskoppeling uit stap 2 is genoeg. Gebruik je een patroon met aangenomen rollen, maak dan een agency aan (IAM → Agencies → Create Agency) met het volgende:
- Agency type: Account (een clouddienst van een ander T Cloud Public-account is hier niet van toepassing).
- Delegated party: kies de OpenID Connect-identity provider die je in stap 1 hebt aangemaakt.
- Permissions: koppel het beleid dat de CI-job nodig heeft (bijv.
OBS Administrator, beperkt tot de OBS-bucket van de workload, ofCCE FullAccess, beperkt tot het project van de workload).
Noteer de naam van de agency en het project waartoe je haar beperkt.
Stap 5: gebruik de inloggegevens in een workflow
De runner haalt een ID-token op, wisselt dat bij het OS-FEDERATION-endpoint van OTC in voor een Keystone-token zonder bereik, en ruilt dat vervolgens voor een token met projectbereik. Zowel de CLI van T Cloud Public (otc) als OpenTofu met de provider opentelekomcloud accepteren OS_AUTH_TOKEN uit de omgeving zonder verdere instellingen.
# Forgejo-specific: opts the task into the OIDC envelope.
# Forgejo jobparser only reads this top-level key — it does NOT
# auto-derive from `permissions: id-token: write` like GitHub does.
enable-openid-connect: true
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: fremforge
steps:
- name: Exchange OIDC for T Cloud Public token
run: |
# 1. Fetch the runner OIDC JWT
JWT=$(curl -sS --fail \
-H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://frem.sh" \
| jq -r .value)
# 2. Exchange at OTC's OS-FEDERATION endpoint (NOT /v3/auth/tokens
# with methods=["id_token"] — OTC's Keystone fork doesn't support
# that. Use the IdP-scoped URL with Bearer header instead).
UNSCOPED=$(curl -sS -i \
-X POST -H "Authorization: Bearer $JWT" \
"https://iam.eu-de.otc.t-systems.com/v3/OS-FEDERATION/identity_providers/fremforge-runner-oidc/protocols/oidc/auth" \
| awk 'BEGIN{IGNORECASE=1} /^x-subject-token:/ { sub(/^x-subject-token:[ \t]*/,"",$0); gsub(/\r/,"",$0); print }')
# 3. Swap for project-scoped (the unscoped token gives you no
# permissions on its own; you need a project scope to do anything).
SCOPED=$(curl -sS -i -X POST \
-H "Content-Type: application/json" \
-d "{\"auth\":{\"identity\":{\"methods\":[\"token\"],\"token\":{\"id\":\"$UNSCOPED\"}},\"scope\":{\"project\":{\"name\":\"eu-de\"}}}}" \
"https://iam.eu-de.otc.t-systems.com/v3/auth/tokens" \
| awk 'BEGIN{IGNORECASE=1} /^x-subject-token:/ { sub(/^x-subject-token:[ \t]*/,"",$0); gsub(/\r/,"",$0); print }')
echo "::add-mask::$SCOPED"
echo "OS_AUTH_TOKEN=$SCOPED" >> $GITHUB_ENV
- name: Tofu plan
run: tofu plan
# opentelekomcloud provider picks up OS_AUTH_TOKEN automaticallyOpmerkingen over de specifieke kenmerken van T Cloud Public
- OTC gebruikt
/v3/OS-FEDERATION/identity_providers/{idp}/protocols/oidc/auth, NIET/v3/auth/tokensmetmethods=["id_token"]. De authenticatiemethode in de body uit upstream OpenStack geeft op de Keystone-fork van OTC400 "Unsupported method: id_token". Empirisch geverifieerd en volgens API-documentiam_13_0606van OTC. - OTC roteert de JWKS niet automatisch. Je plakt de ondertekeningssleutel eenmalig bij het aanmaken van de provider en opnieuw wanneer fremforge een rotatie aankondigt. AWS, Azure en GCP halen hem allemaal automatisch op uit het discoverydocument; alleen T Cloud Public vereist het expliciet plakken.
- Het ingewisselde token staat in de responsheader
X-Subject-Token, niet in de body; een conventie van OpenStack-Keystone. - De afbakening per workload komt van de claim
deployer_group(de mapping koppelt de gefedereerde gebruiker aan die groep) EN van de projectrollen op die groep. De claim voorkomt dat de verkeerde workload de verkeerde groep aanneemt; de rol beperkt wat de groep kan doen. - Optioneel: agencies voor patronen met aangenomen rollen worden ook ondersteund, maar de meeste toepassingen hebben ze niet nodig; de groepskoppeling uit stap 2 is genoeg.
AWS IAM
Stap 1: maak een OIDC-identity provider aan
Ga in de AWS-console naar IAM → Identity providers → Add provider.
- Provider type: OpenID Connect
- Provider URL:
https://frem.sh/_app/runner/oidc(één globale issuer; filteren per organisatie gebeurt in de voorwaarde van het vertrouwensbeleid, niet in de provider-URL) - Audience:
https://frem.sh
AWS haalt de JWKS op uit het discoverydocument om tokens te verifiëren.
Stap 2: maak een IAM-rol aan met een vertrouwensbeleid voor web identity
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<account-id>:oidc-provider/frem.sh/_app/runner/oidc"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"frem.sh/_app/runner/oidc:aud": "https://frem.sh",
"frem.sh/_app/runner/oidc:repository_owner": "<your-org>",
"frem.sh/_app/runner/oidc:sub": "repo:<your-org>/<your-repo>:ref:refs/heads/main"
}
}
}
]
}Koppel de rechten die de CI-job nodig heeft aan deze rol (bijv. AmazonS3FullAccess, AmazonECRPowerUser).
Stap 3: gebruik het in een workflow
Gebruik de officiële action aws-actions/configure-aws-credentials:
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: fremforge
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::<account-id>:role/<role-name>
aws-region: eu-central-1
audience: https://frem.sh
- name: Deploy
run: aws s3 sync ./dist s3://my-bucket/De action regelt automatisch het ophalen van het token, de aanroep sts:AssumeRoleWithWebIdentity en het injecteren van de inloggegevens.
Azure (Entra Workload Identity)
Stap 1: maak gefedereerde inloggegevens aan op een app-registratie
- Ga in de Azure-portal naar Entra ID → App registrations →
<your app>→ Certificates & secrets → Federated credentials. - Klik op Add credential.
- Scenario: Other issuer.
- Vul in:
- Issuer:
https://frem.sh/_app/runner/oidc(één globale issuer; de isolatie per organisatie wordt afgedwongen door de Subject identifier hieronder) - Subject identifier:
repo:<your-org>/<your-repo>:ref:refs/heads/main - Audience:
https://frem.sh
- Issuer:
- Sla op.
Stap 2: gebruik het in een workflow
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: fremforge
steps:
- uses: actions/checkout@v4
- name: Get OIDC token
run: |
TOKEN=$(curl -sS \
-H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://frem.sh" \
| jq -r .value)
echo "OIDC_TOKEN=$TOKEN" >> $GITHUB_ENV
- name: Azure login via federated token
run: |
az login \
--service-principal \
--tenant <tenant-id> \
--client-id <client-id> \
--federated-token "$OIDC_TOKEN"
- name: Deploy
run: az webapp deploy --resource-group my-rg --name my-app --src-path ./distDe client-ID van de app-registratie en de ID van je Entra-tenant zijn geen secrets. Je kunt ze als gewone workflowvariabelen opslaan. Alleen het OIDC-token is gevoelig, en dat verloopt zodra de job klaar is.
GCP Workload Identity
Stap 1: maak een Workload Identity-pool en een OIDC-provider aan
# Create the pool
gcloud iam workload-identity-pools create fremforge-pool \
--location global \
--display-name "fremforge CI"
# Create the OIDC provider inside the pool
gcloud iam workload-identity-pools providers create-oidc fremforge-provider \
--location global \
--workload-identity-pool fremforge-pool \
--issuer-uri "https://frem.sh/_app/runner/oidc" \
--allowed-audiences "https://frem.sh" \
--attribute-mapping "google.subject=assertion.sub,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner"Stap 2: sta impersonatie van het serviceaccount toe
# Allow the pool to impersonate a service account, scoped by sub claim
gcloud iam service-accounts add-iam-policy-binding <sa>@<project>.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "principalSet://iam.googleapis.com/projects/<project-number>/locations/global/workloadIdentityPools/fremforge-pool/attribute.sub/repo:<your-org>/<your-repo>:ref:refs/heads/main"Stap 3: gebruik het in een workflow
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: fremforge
steps:
- uses: actions/checkout@v4
- name: Authenticate to GCP via OIDC
uses: google-github-actions/auth@v2
with:
workload_identity_provider: projects/<project-number>/locations/global/workloadIdentityPools/fremforge-pool/providers/fremforge-provider
service_account: <sa>@<project>.iam.gserviceaccount.com
audience: https://frem.sh
- name: Deploy
run: gcloud run deploy my-service --image gcr.io/my-project/my-imageDe action google-github-actions/auth werkt op de runners van fremforge. Ze gebruikt hetzelfde mechanisme met ACTIONS_ID_TOKEN_REQUEST_TOKEN / ACTIONS_ID_TOKEN_REQUEST_URL.
Problemen oplossen
Audience komt niet overeen.
De claim aud in het token moet overeenkomen met wat de provider verwacht. Is het vertrouwensbeleid of de provider ingesteld op een andere audience (bijv. sts.amazonaws.com in plaats van https://frem.sh), dan mislukt het inwisselen met een validatiefout voor de audience. Zet audience: https://frem.sh expliciet in de instellingen van de provider en in het tokenverzoek (gebruik &audience=https://frem.sh in de curl-URL).
De claim sub komt niet overeen met de voorwaarde in het vertrouwensbeleid.
Het formaat van de claim sub is exact: repo:<org>/<repo>:ref:refs/heads/<branch>. Veelvoorkomende afwijkingen:
- Tikfout in de branchnaam (
mainofmaster). - Het vertrouwensbeleid gebruikt een tag-ref (
refs/tags/v1.0), maar de job draait op een branch. - Het beleid gebruikt
refs/heads/main, maar de job draait op een PR-branch (refs/pull/42/head). GebruikStringLikemet een jokerteken als je PR’s wilt toestaan:"repo:acme/api:ref:refs/pull/*".
Token verlopen bij jobs die langer dan 1 uur duren.
Het OIDC-token heeft een TTL van 1 uur. Jobs die langer dan 1 uur draaien, krijgen elke keer dat ze het tokenendpoint aanroepen een nieuw token. Elke stap die ACTIONS_ID_TOKEN_REQUEST_URL aanroept, krijgt een nieuw token. Bewaar je het token in een cache over stappen die samen langer dan 1 uur duren, dan verloopt het. Haal bij elke stap die inloggegevens nodig heeft een nieuw token op.
Recht id-token: write ontbreekt.
Is permissions: niet ingesteld in de workflow of de job, dan gebruikt de runner de standaardset met alleen-lezen rechten, en daar zit id-token: write niet in. De variabele ACTIONS_ID_TOKEN_REQUEST_TOKEN ontbreekt dan en het tokenverzoek geeft 403. Voeg id-token: write toe aan het permissions:-blok op jobniveau (of op workflowniveau als alle jobs het nodig hebben).
Federatie-instellingen per organisatie overschrijven
Op de beheerpagina https://frem.sh/<org>/_admin/runner-federation lees je de federatie-instellingen van je organisatie en scherp je ze aan als dat nodig is.
Voor de meeste opstellingen heb je alleen de uitgever-URL nodig: kopieer die van deze pagina naar het vertrouwensbeleid van je cloud (het veld Provider/Issuer URL bij AWS, Azure, GCP, Scaleway enz.). De pagina toont ook de JWKS-URL voor providers die het discoverydocument niet automatisch ophalen (T Cloud Public vereist expliciet plakken; AWS, Azure en GCP halen hem automatisch op).
Onder Geavanceerde overschrijvingen op dezelfde pagina kun je:
allowed_audiencesvastleggen: een harde allowlist vanaud-waarden die de issuer ondertekent. Gebruik dit als je alleen tokens wilt uitgeven voor specifieke vertrouwensbeleidsregels in de cloud en elke per ongeluk ruimere audience wilt blokkeren.- Een eigen sjabloon voor de claim
subinstellen: als je bestaande vertrouwensbeleid een andere vorm vansubverwacht dan de standaard van fremforge.
De meeste klanten laten de geavanceerde overschrijvingen op hun standaardwaarden staan en gebruiken alleen de uitgever-URL. Dezelfde instellingen zijn ook programmatisch beschikbaar; zie hieronder.
Federatie-instellingen per organisatie via de API
Standaard ondertekent de issuer tokens met de claimvorm van het platform (sub = repo:<org>/<repo>:ref:<ref>, geen beperking op aud). Met twee instellingen leg je per organisatie strengere afspraken vast:
allowed_audiences: een harde allowlist vanaud-waarden die de issuer ondertekent. Elk verzoek om een token met eenaudbuiten de lijst wordt geweigerd voordat de JWT wordt aangemaakt. Handig als je tokens wilt uitgeven voor vertrouwensbeleid in AWS en T Cloud Public, maar elke per ongeluk ruimere audience-claim wilt blokkeren. Lege lijst = geen beperking (standaard van het platform).sub_claim_template: een sjabloon in Mustache-stijl dat bij het uitgeven van het token wordt ingevuld met vier waarden ({{tenant}},{{repo}},{{branch}},{{ref_type}}). Handig als je bestaande vertrouwensbeleid voor GitHub Actions / Bitbucket Pipelines een andere vorm vansubverwacht dan de standaard van fremforge.
De huidige instellingen lezen
curl -H "Authorization: Bearer $FREMFORGE_PAT" \
https://frem.sh/_app/api/v1/orgs/acme/runners/federation
# {
# "issuer": "https://frem.sh/runner/oidc",
# "jwks_uri": "https://frem.sh/runner/oidc/.well-known/jwks.json",
# "tenant_org_slug": "acme",
# "allowed_audiences": [],
# "sub_claim_template": null
# }allowed_audiences vastleggen
curl -X PUT -H "Authorization: Bearer $FREMFORGE_PAT" \
-H "Content-Type: application/json" \
-d '{
"allowed_audiences": [
"sts.amazonaws.com",
"sts.eu-west-1.amazonaws.com"
]
}' \
https://frem.sh/_app/api/v1/orgs/acme/runners/federationDaarna wordt elke poging om een token uit te geven met een aud die niet in de lijst staat, geweigerd, en faalt de job dicht met een fout dat de audience is geweigerd. Vereiste PAT-scope: runners:write.
sub_claim_template aanpassen
curl -X PUT -H "Authorization: Bearer $FREMFORGE_PAT" \
-H "Content-Type: application/json" \
-d '{
"sub_claim_template": "tenant:{{tenant}}:repo:{{repo}}:branch:{{branch}}"
}' \
https://frem.sh/_app/api/v1/orgs/acme/runners/federationDit zijn de vier ondersteunde vervangingen:
| Token | Wordt | Voorbeeld |
|---|---|---|
{{tenant}} | De slug van de organisatie | acme |
{{repo}} | <org>/<repo> | acme/api |
{{branch}} | Branchnaam (alleen als ref_type=branch; leeg voor tags) | main |
{{ref_type}} | branch of tag | branch |
Onbekende plaatshouders blijven letterlijk staan in de uitvoer; {{nope}} blijft bijvoorbeeld {{nope}} in de ingevulde sub. Dat is bewust: een verkeerd ingesteld sjabloon faalt dan duidelijk zichtbaar bij het matchen met het vertrouwensbeleid, in plaats van ongemerkt een lege tekenreeks uit te geven.
Terugzetten naar de standaardwaarden
Stuur een lege allowed_audiences en null als sub_claim_template:
curl -X PUT -H "Authorization: Bearer $FREMFORGE_PAT" \
-H "Content-Type: application/json" \
-d '{ "allowed_audiences": [], "sub_claim_template": null }' \
https://frem.sh/_app/api/v1/orgs/acme/runners/federationAlle wijzigingen worden vastgelegd in het auditlog van de organisatie onder runner_federation.updated. De momentopname van de body laat het volledige sub_claim_template weg, maar legt wel vast of er een is ingesteld.
Scaleway IAM External App
Scaleway is een EU-soevereine cloud met hoofdkantoor in Frankrijk en dataresidentie in FR / NL / PL. De IAM-bouwsteen External Apps (GA sinds oktober 2024) accepteert een upstream-OIDC-IdP en laat je workloadprincipals koppelen via JWT-claims; dezelfde federatievorm die AWS, GCP en Azure bieden.
Stap 1: maak een IAM External App aan
In de Scaleway-console: IAM → External Apps → Add an External App. Stel in:
- Issuer URL: de issuer-URL van fremforge uit de wizard (bijv.
https://frem.sh/_app/runner/oidc). - JWKS URI: de JWKS-URI van fremforge.
- Subject mapping: koppel op
sub. Beperk tot één repository als dat kan (repo:<your-slug>/<repo>:*). - Audience: de URN van je Scaleway-organisatie (
scw:org:<org-id>).
Stap 2: koppel een Policy
Koppel een Scaleway-Policy aan de External App die de acties toestaat die je CI nodig heeft. Beperk die tot één Project voor minimale rechten.
Stap 3: gebruik het in een workflow
permissions:
id-token: write
steps:
- name: Get the fremforge OIDC token
run: |
TOKEN=$(curl -sS \
-H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=scw:org:<org-id>" \
| jq -r .value)
echo "::add-mask::$TOKEN"
echo "FF_TOKEN=$TOKEN" >> $GITHUB_ENV
- name: Exchange for Scaleway STS keys
run: |
# POST $FF_TOKEN to Scaleway's External-App token endpoint and export the
# returned short-lived keys. See the Scaleway IAM docs for the exact shape.
./scripts/scw-sts-exchange.sh # writes SCW_ACCESS_KEY / SCW_SECRET_KEY
- name: Deploy
run: ./deploy.shDe vorm van het endpoint voor het inwisselen van tokens staat in de IAM-documentatie van Scaleway; de External App geeft kortlevende sleutels in STS-stijl uit, gekoppeld aan het OIDC-subject.
Generieke OIDC-broker (Authentik, Keycloak)
Voor opstellingen waarin de cloud niet rechtstreeks workload-OIDC spreekt (oudere zakelijke doelen die alleen SAML kennen, on-premises deployers, vertrouwensoverzichten voor meerdere clouds die centraal worden beheerd), gebruik je een broker: Authentik, Keycloak, of een andere opstelling met een OIDC-RP en een downstream-RP.
Wanneer je een broker gebruikt
- Je draait al Authentik / Keycloak voor SSO van mensen en wilt CI-workloads onder dezelfde federatie brengen.
- Je wilt één registratie van vertrouwensbeleid beheren, niet N per cloud. Een nieuwe cloud toevoegen is dan “een nieuwe Authentik-provider toevoegen”, niet “het vertrouwensbeleid in elke cloud opnieuw instellen”.
- Je doel kent alleen SAML (sommige gereguleerde on-premises systemen). De broker vormt de brug van OIDC naar SAML.
- Je richt je op een cloud zonder volwaardige workload-OIDC (Stackit, OVH, Hetzner): federeer via de broker in plaats van te wachten op volwaardige ondersteuning.
Stap 1: voeg fremforge toe als upstream-bron
In Authentik: Directory → Federation → OAuth/OIDC Source. Stel in:
- OIDC Provider: de issuer-URL uit de wizard.
- Audience: laat leeg of stel in volgens je downstream-provider.
- Scopes:
openidis genoeg; tokens van fremforge bevatten geen profile- of email-scopes.
Het equivalent in Keycloak is Identity Providers → OpenID Connect v1.0 met Use JWKS URL ingeschakeld.
Stap 2: koppel claims aan lokale groepen / rollen
In Authentik: Customisation → Property Mappings → OIDC. Koppel de sub van de runner-JWT (vorm repo:<slug>/<repo>:ref:refs/heads/<branch>) met een kleine Python-expressie aan lokale groepen:
# Example: anyone deploying main → 'prod-deploy' group
import re
if re.match(r'^repo:[^/]+/[^:]+:ref:refs/heads/main$', token.get('sub', '')):
return ['prod-deploy']
return []Stap 3: gebruik de broker als issuer voor de downstream-cloud
Het vertrouwensbeleid van je cloud matcht dan op een token dat door Authentik is ondertekend, niet rechtstreeks door fremforge. Audience = de client_id van de Authentik-provider. Wissel de JWT van fremforge in voor een door Authentik ondertekende JWT via het endpoint /application/o/token/ van Authentik:
permissions:
id-token: write
steps:
- name: Get fremforge runner OIDC token
run: |
TOKEN=$(curl -sS \
-H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=<authentik-provider-client-id>" \
| jq -r .value)
echo "::add-mask::$TOKEN"
echo "FF_TOKEN=$TOKEN" >> $GITHUB_ENV
- name: Exchange for Authentik token
id: ak-token
run: |
curl -fsS -X POST https://idp.acme.com/application/o/token/ \
-d grant_type=urn:ietf:params:oauth:grant-type:token-exchange \
-d subject_token=$FF_TOKEN \
-d subject_token_type=urn:ietf:params:oauth:token-type:jwt \
-d audience=<downstream-rp> \
| jq -r .access_token > /tmp/ak-token
- name: Deploy
env:
BROKER_TOKEN: $(cat /tmp/ak-token)
run: ./deploy.shAfweging
De broker is een extra tussenstap in het pad van runner naar cloud (meer latentie, één plek meer om te debuggen). Hij verdient zich terug als je ≥3 clouds hebt, gereguleerde SAML-doelen, of al een broker draait voor SSO van mensen. Federeer bij opstellingen met één cloud rechtstreeks naar die cloud (zie de secties hierboven).
Zie ook
- CI-runners: referentie voor gehoste en eigen runners
- Secrets: langlevende inloggegevens opslaan en afbakenen
- Beveiliging: het isolatiemodel van runners en de beveiliging van de toeleveringsketen