Secrets och miljövariabler
Secrets är krypterade värden som skickas in i arbetsflödets jobb som miljövariabler. De går bara att skriva efter att de har skapats. Värdet kan aldrig läsas tillbaka via gränssnittet eller API:t. Den här sidan beskriver nivåer, hur du skapar secrets, användning i arbetsflöden, rotation och gränser.
Secrets krypteras i vila med T Cloud Public DEW KMS och dekrypteras först när jobbet körs på runnern.
Secrets på organisationsnivå hanteras i organisationens administration på frem.sh/<org>/_admin/secrets. Secrets på repo-nivå finns under varje repos Inställningar → Actions → Hemligheter i Forgejo. Miljöer, med sina secrets, variabler, branch-regler och granskare, hanteras i organisationens administration på frem.sh/<org>/_admin/environments. fremforge ger ett jobb miljöns secrets när jobbet lämnas till en runner och tillämpar där företrädesordningen (miljö, sedan repo, sedan organisation).
Nivåer
| Nivå | Var den ställs in | Tillgänglig för |
|---|---|---|
| Organisationssecret | Organisationens administration → Secrets | Alla repon i organisationen |
| Repo-secret | Repots Inställningar → Hemligheter | Bara det repot |
| Avgränsad CI-secret | API:t /orgs/<org>/ci-secrets (sida i organisationens administration: kommer) | Jobb vars arbetsflöde, jobb, branch eller tagg, händelse och miljö secretens avgränsning tillåter, och bara när jobbet hänvisar till den (nedan) |
| Miljösecret | Organisationens administration → Miljöer → <miljö> | Jobb som deklarerar environment: <env>, på en branch eller tagg som miljön tillåter, och bara de secrets som jobbet hänvisar till (nedan) |
Företrädesordning: en miljösecret går före en avgränsad secret knuten till ett repo, som går före en avgränsad secret för hela organisationen, som går före en repo-secret, som går före en organisationssecret. När samma namn finns på flera nivåer vinner den mest specifika nivån.
Skapa secrets
Via gränssnittet: gå till rätt nivå, scrolla till Lägg till eller uppdatera en secret, ange namn (enligt konventionen UPPER_SNAKE_CASE) och värde och klicka på Spara secret.
Via API:t:
# Org secret
curl -X PUT \
-H "Authorization: Bearer <PAT>" \
-H "Content-Type: application/json" \
-d '{"name":"MY_SECRET","data":"the-value"}' \
https://frem.sh/_app/api/v1/orgs/<org>/actions/secrets/MY_SECRET
# Repo secret
curl -X PUT \
-H "Authorization: Bearer <PAT>" \
-H "Content-Type: application/json" \
-d '{"name":"MY_SECRET","data":"the-value"}' \
https://frem.sh/api/v1/repos/<org>/<repo>/actions/secrets/MY_SECRETSecrets går bara att skriva efter att de har skapats. Du kan inte läsa tillbaka värdet för en secret via API:t eller gränssnittet. Du kan bara skriva över den eller ta bort den.
Använda secrets i arbetsflöden
Hänvisa till secrets med ${{ secrets.NAME }}. Secrets är tillgängliga som miljövariabler.
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
steps:
- name: Deploy
env:
API_KEY: ${{ secrets.DEPLOY_API_KEY }}
run: ./deploy.shSecrets maskeras i loggar: all loggutdata som exakt matchar värdet för en secret ersätts med ***. Maskeringen gäller bara exakta träffar; varianter av värdet som är base64-kodade, URL-kodade eller omvandlade på annat sätt maskeras inte automatiskt.
Miljösecrets och driftsättningsgrindar
Jobb som deklarerar environment: får bara secrets som är avgränsade till den miljön (plus repo- och organisationssecrets). Det är avsiktligt: miljösecrets placerar inloggningsuppgifter för produktion bakom miljöns godkännandeflöde.
jobs:
deploy-prod:
runs-on: fremforge
environment: production # triggers approval gate if reviewers are configured
steps:
- name: Deploy
env:
DB_URL: ${{ secrets.PROD_DB_URL }} # environment secret on 'production'
run: ./deploy.shKonfigurera krav på granskare under Organisationens administration → Miljöer → <miljö>. Jobbet pausas för godkännande innan steget körs; secreten skickas inte in förrän jobbet är godkänt och körs.
Miljönamn matchas utan hänsyn till skiftläge, som i Forgejo och GitHub: environment: Production är miljön production, med dess branch-regel, granskare och secrets. Om två miljöer bara skiljer sig åt i skiftläge används den som stavas exakt som jobbet deklarerar; om ingen av dem gör det får jobbet ingen miljö, och dess driftsättningsgrind nekar det (environment_case_ambiguous). Byt namn på en av dem.
En pull_request_target-körning från en fork får ingen miljö, inga av dess secrets och inget OIDC-claim, oavsett vad jobbet deklarerar. Det är striktare än GitHub. Se Secrets räckvidd för PR från forkar.
Miljösecrets når bara de jobb som hänvisar till dem
Sedan 2026-10-26 får ett jobb en miljösecret bara när jobbet hänvisar till den: i sina egna steg, env:, with: eller if:, eller i arbetsflödets env: på toppnivå, som ${{ secrets.NAME }} eller ${{ secrets['NAME'] }}. En secret som jobbet inte hänvisar till skickas inte alls till dess runner och finns alltså inte på maskinen där jobbet körs.
${{ toJSON(secrets) }}, ett beräknat namn som ${{ secrets[format('{0}_KEY', 'DEPLOY')] }} och secrets: inherit i ett anrop av ett återanvändbart arbetsflöde hänvisar till alla miljöns secrets, som på GitHub.
Ett steg kan bara läsa en secret genom ett sådant uttryck, så ett arbetsflöde som fungerar i dag fortsätter att fungera: ändringen tar bort secrets som inget steg kunde läsa.
Om fremforge inte kan läsa jobbets arbetsflödesfil vid jobbets commit, eller inte hittar jobbet i den, får jobbet inga av miljöns secrets. Jobbet körs ändå, med sin OIDC-token och sina variabler.
Vem fick vilken secret: läsloggen
Varje CI-jobb som får en miljösecret eller avgränsad secret, eller som hänvisar till en som det nekas, skriver en post i organisationens granskningslogg, med åtgärden ci.secret.read:
| Fält | Värde |
|---|---|
| actor | den som startade körningen (organisationen, för en schemalagd körning) |
repository, repository_id, workflow, job | var det kördes |
run_id, run_number, run_attempt, ref, event | vilken körning |
environment | miljön som jobbet deklarerade |
secrets | NAMNEN på de secrets som jobbet fick, var och en med sin nivå (environment, repo eller org) |
withheld | namn som jobbet hänvisade till men inte kunde få, var och en med en orsak: workflow-unreadable eller job-not-found, och för en avgränsad secret det fält i avgränsningen som nekade den (scope-workflow, scope-job, scope-ref, scope-event, scope-environment) eller undecryptable |
Värdet för en secret sparas aldrig, inte heller en hash av det. Ett jobb som inte hänvisar till någon av miljöns secrets får inga och skriver ingen post.
Posten skrivs innan secrets lämnas till runnern. Om den inte kan sparas får jobbet inga av dem: ingen secret lämnar fremforge utan att registreras. fremforges jour larmas när det händer.
Hämta posterna med API:t:
curl -H "Authorization: Bearer $FREMFORGE_TOKEN" \
"https://frem.sh/_app/api/v1/orgs/<org>/audit?action=ci.secret.read&since=2026-10-26"Posterna ingår i granskningsloggens hashkedja, dess lagringstid och dess SIEM-ström, som alla andra poster i granskningsloggen.
Repository- och organisationssecrets som ställs in i Forgejo omfattas inte: Forgejo lämnar fortfarande ut dem till varje jobb i repot, och läsningarna registreras inte. Använd en avgränsad CI-secret i stället och ta bort Forgejo-kopian med samma namn: så länge den finns når den fortfarande de jobb som avgränsningen nekar.
Avgränsade CI-secrets
En avgränsad CI-secret hålls av fremforge, för hela organisationen eller för ett repo, och lämnas till ett jobb bara när alla fält i avgränsningen som du har angett matchar (inom ett fält räcker det att ett av de listade värdena matchar):
| Fält | Matchar | Exempel |
|---|---|---|
workflows | filnamnet för arbetsflödet | deploy.yaml, release-*.yml |
jobs | jobbets id (nyckeln under jobs:) | deploy, publish-* |
refs | branchen eller taggen | refs/heads/main, refs/tags/v* |
events | arbetsflödets trigger | push, workflow_dispatch, schedule, pull_request, pull_request_target, release |
environment | jobbet deklarerar den här miljön, på en branch eller tagg som miljön tillåter | production |
* är det enda jokertecknet. Ett fält som du utelämnar släpper igenom allt, med ett undantag: när inga events är listade får en körning på en pull requests ref (refs/pull/...) aldrig secreten. För att ge kod i en pull request en avgränsad secret listar du pull_request (eller pull_request_target) uttryckligen.
Jobbet måste också hänvisa till secreten (se ovan). Varje leverans, och varje nekad secret som jobbet hänvisade till, registreras i jobbets post ci.secret.read. En pull request från en fork får aldrig någon.
Vilka fält som är en säkerhetsgräns. Den som kan pusha till repot kan skapa en branch vars arbetsflöde har ett jobb med namnet deploy i en fil med namnet deploy.yaml, och starta det. Så workflows och jobs begränsar vilka kodvägar som normalt får secreten, men de skyddar den inte mot personer med skrivåtkomst. Det gör refs (peka på skyddade branches eller taggar) och environment (med en branch-regel och krav på granskare). Det är samma sak som på GitHub.
En körning i merge-kön (refs/heads/fremforge-queue/...) är ett bygge i samma repo som en maintainer har köat, och en tom refs-avgränsning släpper igenom den, som vilken branch som helst. Begränsa refs om en secret inte får nå körningar i merge-kön.
Jobb i ett återanvändbart arbetsflöde, och, på en Forgejo-version som ännu inte skickar jobbets id, jobb med ett eget name: eller en matris, får ännu inga avgränsade secrets.
Skapa eller ersätt en (värdet går bara att skriva; varje ändring granskas, tillsammans med avgränsningen den ersatte):
curl -X PUT -H "Authorization: Bearer $FREMFORGE_TOKEN" -H 'Content-Type: application/json' \
-d '{"value":"...","workflows":["deploy.yaml"],"jobs":["deploy"],"refs":["refs/heads/main"],"events":["push","workflow_dispatch"]}' \
"https://frem.sh/_app/api/v1/orgs/<org>/ci-secrets/DEPLOY_KEY?repository_id=<forgejo repository id>"Utelämna repository_id för en secret som gäller hela organisationen. Ett okänt fält, en environment som inte är ett namn och en tom post i en lista nekas (400) i stället för att ignoreras, så att ett skrivfel aldrig kan vidga en secret till alla jobb. GET /orgs/<org>/ci-secrets listar namn, avgränsningar och när var och en senast lästes; DELETE .../ci-secrets/<NAME>[?repository_id=] tar bort en. Scopes: ci-secrets:read, ci-secrets:write. Gränser: 500 per organisation, 100 per repo, 20 mönster per fält, 64 KB per värde.
Vill du hantera scoped CI-secrets som kod, använd fremforge_ci_secret i fremforge-providern (från 0.9.0). Värdet är ett write-only-argument och når aldrig Terraform-state.
Rotation av secrets
- Skapa först de nya inloggningsuppgifterna i det externa systemet.
- Skriv över secreten i fremforge med det nya värdet. Ta inte bort den och skapa den på nytt.
- Starta en ny körning av arbetsflödet för att kontrollera att de nya inloggningsuppgifterna fungerar hela vägen.
- Återkalla de gamla inloggningsuppgifterna i det externa systemet.
Att skriva över bevarar verifieringskedjan och undviker ett fönster där secreten saknas för jobb som körs mellan borttagning och nyskapande.
Gränser
| Objekt | Gräns |
|---|---|
| Största storlek på ett värde | 64 KB |
| Organisationssecrets | 1 000 |
| Repo-secrets | 100 per repo |
| Miljösecrets | 100 per miljö |
| Avgränsade CI-secrets | 500 per organisation, 100 per repo |
| Mönster för namn | Bokstäver, siffror och understreck; måste börja med en bokstav; får inte börja med FORGEJO_ eller GITHUB_ |
OIDC som alternativ till secrets
För driftsättning till molnleverantörer (T Cloud Public, AWS, Azure, GCP) bör du överväga OIDC-tokenfederation i stället för långlivade inloggningsuppgifter lagrade som secrets. OIDC utfärdar kortlivade tokens per jobb, avgränsade till den specifika körningen av arbetsflödet. Inget att rotera, inget som kan läcka.
OIDC är det rekommenderade mönstret för alla jobb som driftsätter till molninfrastruktur.
Korsreferenser
- Actions och CI/CD, syntax för arbetsflöden och blocket permissions
- OIDC-tokenfederation, nyckelfria inloggningsuppgifter i molnet
- Organisationens administration, hantering av secrets på organisationsnivå