OIDC-Token-Föderation
Jeder CI-Job in fremforge kann ein kurzlebiges OIDC-Token erhalten: ein mit RS256 signiertes JWT, ausgestellt vom Runner-OIDC-Issuer von fremforge. Cloud-Anbieter (T Cloud Public, AWS, Azure, GCP) lassen sich so konfigurieren, dass sie diesem Token vertrauen und es gegen eingeschränkte, zeitlich begrenzte Zugangsdaten tauschen. Keine als Secrets gespeicherten Deploy-Schlüssel, nichts, was nach Zeitplan rotiert werden muss.
Claim-Referenz
Das Runner-JWT von fremforge enthält die folgenden Claims:
| Claim | Wert / Format | Beispiel |
|---|---|---|
iss | https://frem.sh/_app/runner/oidc (ein globaler Issuer für alle Mandanten) | https://frem.sh/_app/runner/oidc |
sub | repo:<org>/<repo>:ref:refs/heads/<branch> | repo:acme/api:ref:refs/heads/main |
aud | Konfigurierbar; Standard https://frem.sh | https://frem.sh |
repository_owner | Slug der Organisation – binde Bedingungen der Vertrauensrichtlinie an diesen Claim, um Mandanten unter dem gemeinsamen Issuer voneinander zu isolieren | acme |
repository | <org>/<repo> | acme/api |
ref | Vollständige Git-Ref | refs/heads/main |
sha | Commit-SHA | a1b2c3d4... |
environment | Name der Deployment-Umgebung (wenn der Job eine deklariert) | production |
job_workflow_ref | Pfad und Ref der Workflow-Datei | acme/api/.forgejo/workflows/deploy.yaml@refs/heads/main |
deployer_group | (Nur T Cloud Public) Name der IAM-Gruppe, an die der föderierte Benutzer gebunden wird, von fremforge pro Workload gesetzt – siehe Agency-Vertrauen in T Cloud Public | acme-prod-deployers |
Der Claim sub ist in den meisten Vertrauensrichtlinien der Anbieter der primäre Vertrauensanker. Er identifiziert die Kombination aus Organisation, Repository und Branch eindeutig. Für die Isolation von Mandanten in gemeinsam genutzten Cloud-Konten füge eine Bedingung hinzu, die repository_owner (den Slug deiner Organisation) festlegt – dasselbe Muster wie beim Vertrauen von GitHub Actions auf token.actions.githubusercontent.com. fremforge stellt einen einzigen globalen Issuer für alle Mandanten bereit; die Vertrauensisolation wird auf Ebene der Claims durchgesetzt, nicht auf Ebene der Issuer-URL.
Das Token in einem Workflow abrufen
Füge id-token: write zum permissions-Block des Jobs hinzu. Der Runner setzt dann ACTIONS_ID_TOKEN_REQUEST_TOKEN und ACTIONS_ID_TOKEN_REQUEST_URL als Umgebungsvariablen, mit denen du das eigentliche JWT abrufst:
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_ENVDie meisten anbieterspezifischen Schritte (AWS, Azure, GCP) rufen das Token intern ab. Den manuellen Abruf oben schreibst du nur, wenn du das rohe JWT für einen eigenen Vertrauensablauf brauchst.
Agency-Vertrauen in T Cloud Public
Das IAM-Föderationsmodell von T Cloud Public stammt von OpenStack ab: Du registrierst den OIDC-Issuer als Identity Provider, hängst ein Mapping an, das Claims des ID-Tokens in lokale IAM-Gruppen übersetzt, und tauschst dann das ID-Token des Runners am OS-FEDERATION-Endpunkt von OTC gegen ein Keystone-Token von T Cloud Public, das auf die vom Mapping gebundenen Gruppen beschränkt ist.
fremforge nutzt eine claim-gesteuerte Gruppenbindung (dieselbe Form wie AWS Identity Center, GCP Workload Identity Federation und Azure Federated Credentials): Das ID-Token des Runners trägt pro Workload einen Claim deployer_group, und dein OTC-Mapping liest diesen Claim wörtlich. Eine Mapping-Regel deckt deine gesamte Flotte ab – ein neuer Workload berührt dein IAM überhaupt nicht.
Schritt 1: Einen OpenID-Connect-Identity-Provider anlegen
Gehe in der Konsole von T Cloud Public zu IAM → Identity Providers → Create Identity Provider.
- Type: Virtual user
- Protocol: OpenID Connect
- Access type: Programmatic access (
program)
Konfiguriere nach dem Anlegen die OIDC-Einstellungen:
- Identity provider URL (
idp_url):https://frem.sh/_app/runner/oidc(ein globaler Issuer; entspricht dem Claimissin jedem ID-Token eines fremforge-Runners). - Client ID (
client_id):https://frem.sh, muss dem Claimaudim ID-Token des Runners entsprechen. - Signing key (
signing_key): Füge das JWKS-JSON mit den öffentlichen Schlüsseln ein. Rufe es einmalig überhttps://frem.sh/_app/runner/oidc/.well-known/openid-configuration→jwks_uriab und kopiere das JSON. T Cloud Public ruft JWKS nicht automatisch ab; füge es daher erneut ein, wenn fremforge eine JWKS-Rotation ankündigt (angekündigt auf der Trust-Seite; Rotationen höchstens einmal im Jahr).
Schritt 2: Die claim-gesteuerte Mapping-Regel hinzufügen
Eine Regel, die für beliebig viele Workloads skaliert:
[
{
"local": [
{ "user": { "name": "fremforge-{0}-{1}" } },
{ "group": { "name": "{2}" } }
],
"remote": [
{ "type": "repository_owner" },
{ "type": "repository" },
{ "type": "deployer_group" }
]
}
]Die Vertrauenslage:
- Der föderierte Benutzer tritt der IAM-Gruppe bei, deren Namen der Claim
deployer_groupdes ID-Tokens angibt ({2}setzt den Wert des Claims wörtlich ein). - Den Claim setzt der Runner-OIDC-Issuer von fremforge gemäß der Zuordnung von Workload zu Gruppe, die du beim Onboarding vereinbarst. Er kann nur für Workloads ausgestellt werden, für die wir eine Zeile haben, und nur für die Ref, die diese Zeile festlegt (Standard: Branch main).
- Dieselbe Festlegung der JWT-Signatur, dieselbe Filterung nach
iss+aud+repository_owner– nur die Entscheidung über Workload und Gruppe ist von „N OTC-Mapping-Regeln“ zu „einem von fremforge ausgestellten Claim“ gewandert.
Schritt 3: Die IAM-Gruppen anlegen, die deine Workloads übernehmen
Lege eine Gruppe pro Deployer-Profil an, das du bereitstellen willst (z. B. acme-prod-deployers, acme-staging-deployers). Hänge die Projekt- und EPS-Rollen an, die jedes Profil braucht – sie gehören zu 100 % dir; fremforge fasst deine Gruppenkonfiguration nie an. Die Gruppennamen entsprechen dem Wert, den fremforge in den Claim deployer_group schreibt, wie beim Onboarding vereinbart.
Schritt 4: fremforge mitteilen, welcher Workload welche Gruppe nutzt
Per E-Mail oder Aufruf der Admin-API: „Repo acme/api, Branch main → Gruppe acme-prod-deployers.“ fremforge legt eine Zeile in seiner Tabelle runner_deployer_groups an. Ab dem nächsten Workflow-Lauf tragen die ID-Tokens für diesen Workload deployer_group=acme-prod-deployers, und dein Mapping bindet den föderierten Benutzer an diese Gruppe.
Ein neues Repository hinzuzufügen ist nur eine weitere E-Mail – dein OTC-IAM bleibt unverändert.
Optional: Eine Agency zum Übernehmen anlegen
Die meisten Setups überspringen diesen Schritt: Die Gruppenbindung aus Schritt 2 reicht. Wenn du ein Muster mit übernommenen Rollen nutzt, lege eine Agency an (IAM → Agencies → Create Agency) mit folgenden Angaben:
- Agency type: Account (Cloud-Dienst eines anderen T-Cloud-Public-Kontos trifft hier nicht zu).
- Delegated party: Wähle den OpenID-Connect-Identity-Provider, den du in Schritt 1 angelegt hast.
- Permissions: Hänge die Richtlinien an, die der CI-Job braucht (z. B.
OBS Administratorbeschränkt auf den OBS-Bucket des Workloads oderCCE FullAccessbeschränkt auf das Projekt des Workloads).
Notiere den Namen der Agency und das Projekt, auf das du sie beschränkst.
Schritt 5: Die Zugangsdaten in einem Workflow nutzen
Der Runner ruft ein ID-Token ab, tauscht es am OS-FEDERATION-Endpunkt von OTC gegen ein Keystone-Token ohne Geltungsbereich und tauscht dieses dann gegen ein projektbezogenes Token. Sowohl die CLI von T Cloud Public (otc) als auch OpenTofu mit dem Provider opentelekomcloud übernehmen OS_AUTH_TOKEN ohne weitere Konfiguration aus der Umgebung.
# 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 automaticallyHinweise zu den Besonderheiten von T Cloud Public
- OTC nutzt
/v3/OS-FEDERATION/identity_providers/{idp}/protocols/oidc/auth, NICHT/v3/auth/tokensmitmethods=["id_token"]. Die Auth-Body-Methode aus Upstream-OpenStack liefert auf dem Keystone-Fork von OTC400 "Unsupported method: id_token". Empirisch geprüft und laut OTC-API-Dokumentationiam_13_0606. - OTC rotiert JWKS nicht automatisch. Du fügst den Signaturschlüssel einmal beim Anlegen des Providers ein und erneut, wenn fremforge eine Rotation ankündigt. AWS, Azure und GCP rufen ihn automatisch aus dem Discovery-Dokument ab – nur T Cloud Public verlangt das explizite Einfügen.
- Das getauschte Token steht im Antwort-Header
X-Subject-Token, nicht im Body – Konvention von OpenStack Keystone. - Die Beschränkung pro Workload ergibt sich aus dem Claim
deployer_group(das Mapping bindet den föderierten Benutzer an diese Gruppe) UND den Projektrollen dieser Gruppe. Der Claim verhindert, dass der falsche Workload die falsche Gruppe übernimmt; die Rolle begrenzt, was die Gruppe tun darf. - Optional: Agencies für Muster mit übernommenen Rollen werden ebenfalls unterstützt, die meisten Anwendungsfälle brauchen sie aber nicht – die Gruppenbindung aus Schritt 2 reicht.
AWS IAM
Schritt 1: Einen OIDC-Identity-Provider anlegen
Gehe in der AWS-Konsole zu IAM → Identity providers → Add provider.
- Provider type: OpenID Connect
- Provider URL:
https://frem.sh/_app/runner/oidc(ein globaler Issuer; die Filterung pro Mandant erfolgt in der Bedingung der Vertrauensrichtlinie, nicht über die Provider-URL) - Audience:
https://frem.sh
AWS ruft die JWKS aus dem Discovery-Dokument ab, um Tokens zu prüfen.
Schritt 2: Eine IAM-Rolle mit einer Web-Identity-Vertrauensrichtlinie anlegen
{
"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"
}
}
}
]
}Hänge die Berechtigungen, die der CI-Job braucht, an diese Rolle an (z. B. AmazonS3FullAccess, AmazonECRPowerUser).
Schritt 3: In einem Workflow nutzen
Nutze die offizielle 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/Die Action übernimmt den Abruf des Tokens, den Aufruf von sts:AssumeRoleWithWebIdentity und das Einspeisen der Zugangsdaten automatisch.
Azure (Entra Workload Identity)
Schritt 1: Föderierte Anmeldeinformationen für eine App-Registrierung anlegen
- Gehe im Azure-Portal zu Entra ID → App registrations →
<your app>→ Certificates & secrets → Federated credentials. - Klicke auf Add credential.
- Szenario: Other issuer.
- Fülle aus:
- Issuer:
https://frem.sh/_app/runner/oidc(ein globaler Issuer; die Mandantenisolation wird über den Subject identifier unten durchgesetzt) - Subject identifier:
repo:<your-org>/<your-repo>:ref:refs/heads/main - Audience:
https://frem.sh
- Issuer:
- Speichern.
Schritt 2: In einem Workflow nutzen
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 ./distDie Client-ID der App-Registrierung und deine Entra-Tenant-ID sind keine Secrets. Sie können als einfache Workflow-Variablen gespeichert werden. Nur das OIDC-Token ist sensibel, und es läuft nach Abschluss des Jobs ab.
GCP Workload Identity
Schritt 1: Einen Workload-Identity-Pool und einen OIDC-Provider anlegen
# 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"Schritt 2: Die Identitätsübernahme eines Dienstkontos erlauben
# 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"Schritt 3: In einem Workflow nutzen
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-imageDie Action google-github-actions/auth funktioniert auf fremforge-Runnern. Sie nutzt denselben Mechanismus über ACTIONS_ID_TOKEN_REQUEST_TOKEN / ACTIONS_ID_TOKEN_REQUEST_URL.
Fehlerbehebung
Audience stimmt nicht überein.
Der Claim aud im Token muss dem entsprechen, was der Provider erwartet. Sind Vertrauensrichtlinie oder Provider für eine andere Audience konfiguriert (z. B. sts.amazonaws.com statt https://frem.sh), scheitert der Tausch mit einem Fehler bei der Audience-Prüfung. Setze audience: https://frem.sh explizit in der Provider-Konfiguration und in der Token-Anfrage (nutze &audience=https://frem.sh in der curl-URL).
Der Claim sub passt nicht zur Bedingung der Vertrauensrichtlinie.
Das Format des Claims sub ist exakt: repo:<org>/<repo>:ref:refs/heads/<branch>. Häufige Abweichungen:
- Tippfehler im Branch-Namen (
mainstattmaster). - Die Vertrauensrichtlinie nutzt eine Tag-Ref (
refs/tags/v1.0), der Job läuft aber auf einem Branch. - Die Richtlinie nutzt
refs/heads/main, der Job läuft aber auf einem PR-Branch (refs/pull/42/head). NutzeStringLikemit einem Platzhalter, wenn du PRs zulassen musst:"repo:acme/api:ref:refs/pull/*".
Token abgelaufen, Jobs länger als 1 Stunde.
Das OIDC-Token hat eine Gültigkeit von 1 Stunde. Jobs, die länger als 1 Stunde laufen, erhalten bei jedem Aufruf des Token-Endpunkts ein frisches Token. Jeder Schritt, der ACTIONS_ID_TOKEN_REQUEST_URL aufruft, bekommt ein neues Token. Speicherst du das Token über Schritte hinweg zwischen, die mehr als 1 Stunde umfassen, läuft es ab. Rufe in jedem Schritt, der Zugangsdaten braucht, ein frisches Token ab.
Berechtigung id-token: write fehlt.
Ist permissions: im Workflow oder Job nicht gesetzt, nutzt der Runner den standardmäßigen schreibgeschützten Berechtigungssatz, der id-token: write nicht enthält. Die Variable ACTIONS_ID_TOKEN_REQUEST_TOKEN fehlt dann, und die Token-Anfrage liefert 403. Füge id-token: write zum permissions:-Block auf Job-Ebene hinzu (oder auf Workflow-Ebene, wenn alle Jobs es brauchen).
Föderationsüberschreibungen pro Organisation
Auf der Seite der Mandantenverwaltung unter https://frem.sh/<org>/_admin/runner-federation liest du die Föderationseinstellungen deiner Organisation und verschärfst sie bei Bedarf.
Für die meisten Setups brauchst du nur die OIDC-Issuer-URL – kopiere sie von dieser Seite in die Vertrauensrichtlinie deiner Cloud (das Feld Provider/Issuer URL bei AWS, Azure, GCP, Scaleway usw.). Die Seite zeigt außerdem die JWKS-URI für Anbieter, die das Discovery-Dokument nicht automatisch abrufen (T Cloud Public verlangt das explizite Einfügen; AWS, Azure und GCP rufen es automatisch ab).
Unter Erweiterte Überschreibungen auf derselben Seite kannst du:
allowed_audiencesfestlegen – eine harte Allowlist vonaud-Werten, die der Issuer signiert. Nutze sie, wenn du Tokens nur für bestimmte Cloud-Vertrauensrichtlinien ausstellen und jede versehentlich breitere Audience blockieren willst.- Eine eigene Vorlage für den Claim
subsetzen – wenn deine bestehende Vertrauensrichtlinie eine anderesub-Form als den Standard von fremforge erwartet.
Die meisten Kunden belassen die erweiterten Überschreibungen auf ihren Standardwerten und nutzen nur die Issuer-URL. Dieselben Einstellungen sind auch programmatisch verfügbar – siehe unten.
Föderationsüberschreibungen pro Organisation über die API
Standardmäßig signiert der Issuer Tokens mit der Claim-Form der Plattform (sub = repo:<org>/<repo>:ref:<ref>, keine Beschränkung von aud). Mit zwei Stellschrauben legst du pro Mandant engere Verträge fest:
allowed_audiences, eine harte Allowlist vonaud-Werten, die der Issuer signiert. Jede Anfrage mit einemaudaußerhalb der Liste wird abgelehnt, bevor das JWT erzeugt wird. Nützlich, wenn du Tokens für Vertrauensrichtlinien von AWS und T Cloud Public ausstellen, aber jeden versehentlich breiteren Audience-Claim blockieren willst. Leere Liste = keine Beschränkung (Standard der Plattform).sub_claim_template, eine Vorlage im Mustache-Stil, die beim Ausstellen des Tokens mit vier Platzhaltern ({{tenant}},{{repo}},{{branch}},{{ref_type}}) gerendert wird. Nützlich, wenn deine bestehende Vertrauensrichtlinie für GitHub Actions oder Bitbucket Pipelines eine anderesub-Form als den Standard von fremforge erwartet.
Die aktuellen Überschreibungen lesen
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 festlegen
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/federationDanach wird jeder Versuch, ein Token mit einem aud außerhalb der Liste auszustellen, abgelehnt, und der Job scheitert geschlossen mit einem Fehler wegen abgelehnter Audience. Benötigter PAT-Scope: runners:write.
sub_claim_template anpassen
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/federationDie vier unterstützten Ersetzungen sind:
| Platzhalter | Wird zu | Beispiel |
|---|---|---|
{{tenant}} | Der Slug der Organisation | acme |
{{repo}} | <org>/<repo> | acme/api |
{{branch}} | Branch-Name (nur bei ref_type=branch; leer bei Tags) | main |
{{ref_type}} | branch oder tag | branch |
Unbekannte Platzhalter bleiben in der Ausgabe wörtlich stehen; {{nope}} bleibt zum Beispiel im gerenderten sub als {{nope}} erhalten. Das ist Absicht: Eine falsch konfigurierte Vorlage scheitert laut beim Abgleich mit der Vertrauensrichtlinie, statt stillschweigend eine leere Zeichenkette auszugeben.
Auf die Standardwerte zurücksetzen
Sende ein leeres allowed_audiences und null für 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 Änderungen werden im Audit-Log des Mandanten unter runner_federation.updated erfasst. Die Momentaufnahme des Bodys lässt die vollständige sub_claim_template weg, hält aber fest, ob eine gesetzt war.
Scaleway IAM External App
Scaleway ist eine souveräne EU-Cloud mit Hauptsitz in Frankreich und Datenhaltung in FR / NL / PL. Ihr IAM-Baustein External Apps (GA seit Oktober 2024) akzeptiert einen vorgelagerten OIDC-IdP und lässt dich Workload-Prinzipale über JWT-Claims binden – dieselbe Föderationsform, die AWS, GCP und Azure anbieten.
Schritt 1: Eine IAM External App anlegen
In der Scaleway-Konsole: IAM → External Apps → Add an External App. Konfiguriere:
- Issuer URL, die Issuer-URL von fremforge aus dem Assistenten (z. B.
https://frem.sh/_app/runner/oidc). - JWKS URI, die JWKS-URI von fremforge.
- Subject mapping, an
subbinden. Wenn möglich auf ein Repository beschränken (repo:<your-slug>/<repo>:*). - Audience, die URN deiner Scaleway-Organisation (
scw:org:<org-id>).
Schritt 2: Eine Policy anhängen
Hänge der External App eine Scaleway-Policy an, die die Aktionen gewährt, die deine CI braucht. Beschränke sie für minimale Rechte auf ein einzelnes Project.
Schritt 3: In einem Workflow nutzen
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.shDie Form des Token-Exchange-Endpunkts ist in der Scaleway-IAM-Dokumentation beschrieben; der External-App-Baustein gibt kurzlebige Schlüssel im STS-Stil aus, die an das OIDC-Subject gebunden sind.
Generischer OIDC-Broker (Authentik, Keycloak)
Für Setups, in denen die Cloud Workload-OIDC nicht direkt spricht (ältere Enterprise-Ziele nur mit SAML, On-Premises-Deployer, zentral gepflegte Vertrauenszuordnungen über mehrere Clouds), nutze einen Broker: Authentik, Keycloak oder ein beliebiges Setup aus OIDC-RP mit nachgelagertem RP.
Wann ein Broker sinnvoll ist
- Du betreibst Authentik / Keycloak bereits für das SSO von Menschen und willst CI-Workloads unter dieselbe Föderationsoberfläche bringen.
- Du willst eine einzige Registrierung einer Vertrauensrichtlinie verwalten, nicht N pro Cloud. Eine neue Cloud bedeutet dann „einen neuen Authentik-Provider hinzufügen“, nicht „die Vertrauensrichtlinie in jeder Cloud neu aufsetzen“.
- Dein Ziel spricht nur SAML (manche regulierten On-Premises-Systeme). Der Broker überbrückt OIDC → SAML.
- Du zielst auf eine Cloud ohne erstklassiges Workload-OIDC (Stackit, OVH, Hetzner) – föderiere über den Broker, statt auf erstklassige Unterstützung zu warten.
Schritt 1: fremforge als vorgelagerte Quelle hinzufügen
In Authentik: Directory → Federation → OAuth/OIDC Source. Setze:
- OIDC Provider, die Issuer-URL aus dem Assistenten.
- Audience, leer lassen oder passend zu deinem nachgelagerten Provider setzen.
- Scopes,
openidgenügt; fremforge-Tokens tragen keine Profile- oder E-Mail-Scopes.
Das Gegenstück in Keycloak ist Identity Providers → OpenID Connect v1.0 mit aktiviertem Use JWKS URL.
Schritt 2: Claims auf lokale Gruppen / Rollen abbilden
In Authentik: Customisation → Property Mappings → OIDC. Bilde den Claim sub des Runner-JWT (Form repo:<slug>/<repo>:ref:refs/heads/<branch>) mit einem kleinen Python-Ausdruck auf lokale Gruppen ab:
# 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 []Schritt 3: Den Broker als Issuer für die nachgelagerte Cloud nutzen
Die Vertrauensrichtlinie deiner Cloud prüft dann ein Token, das von Authentik signiert ist, nicht direkt von fremforge. Audience = die client_id des Authentik-Providers. Tausche das fremforge-JWT über den Endpunkt /application/o/token/ von Authentik gegen ein von Authentik signiertes JWT:
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.shAbwägung
Der Broker ist ein zusätzlicher Hop auf dem Weg vom Runner zur Cloud (mehr Latenz, eine weitere Stelle zum Debuggen). Er lohnt sich, wenn du ≥3 Clouds, regulierte SAML-Ziele hast oder bereits einen Broker für das SSO von Menschen betreibst. Bei Setups mit nur einer Cloud föderierst du direkt mit der Cloud (siehe die Abschnitte oben).
Querverweise
- CI-Runner, Referenz für gehostete und eigene Runner
- Secrets, langlebige Zugangsdaten speichern und eingrenzen
- Sicherheit, Isolationsmodell der Runner und Sicherheit der Lieferkette