7 små regler for secrets der redder dit team fra kaos

7 små regler for secrets der redder dit team fra kaos

Secrets er ikke magi – det er bare ting du ville fortryde at lægge på Twitter

At håndtere secrets i et team er lidt som at have en nøgle til opgangen i et kollektiv. Alle skal kunne komme ind, men ingen har lyst til at være den, der mister nøglen og får en sur mail fra viceværten.

API keys, database-logins og tokens føles hurtigt som sådan noget “det ordner vi senere”. Indtil en .env-fil ryger med op på GitHub, eller nogen deler produktions-nøglen i en Slack-tråd, der aldrig forsvinder igen.

Jeg går igennem en lille playbook her: hvad et secret egentlig er, hvordan I bruger .env uden at lække alt, hvordan GitHub Actions og hosting-secrets spiller ind, og hvad I gør, når noget allerede er gået galt. Alt med udgangspunkt i et lille team uden enterprise-budget.

1. Hvad er et secret – og hvad er bare kedelig config?

Første regel: alt er ikke et secret. Hvis alt er hemmeligt, er intet det i praksis, for så ender det hele som kaos i en README eller i en tilfældig chat.

Typiske secrets:

  • API nøgler (Stripe, SendGrid, Maps, osv.)
  • Database credentials (brugernavn, password, connection string)
  • JWT secret keys eller andre signeringsnøgler
  • SSH-nøgler, private keys, OAuth client secrets

Typisk config, som ikke er secret:

  • Feature flags (“SHOW_NEW_NAV” = true)
  • Miljønavne (“NODE_ENV” = development / production)
  • Offentlige API base-URLs

En simpel test: ville du have det ok med at lægge værdien i et offentligt GitHub repo? Hvis svaret er nej, så er det et secret. Hvis du er i tvivl, så er det som regel også et secret. Du kan dykke mere ned i forskellen i artiklen om hvordan miljøvariabler ofte bliver misbrugt allerede i udvikling.

2. Baseline i teamet – .env lokalt uden at lække

.env-filer er fine, hvis du accepterer én ting: de må aldrig ryge i git. Aldrig.

Minimum-opsætning for et lille team:

  • En .env lokalt hos hver udvikler
  • En .env.example i repoet uden rigtige secrets
  • .env i .gitignore

Eksempel:

# .env.example
DATABASE_URL=<set i dit lokale miljø>
STRIPE_SECRET_KEY=<ikke commit denne>
NEXT_PUBLIC_API_BASE_URL=https://api.example.com

.env.example hjælper nye folk med at se, hvilke variabler der findes, uden at du deler nøgler i klartekst. Det gør onboarding meget mindre smertefuld.

Og ja, du kommer en dag til at skrive git add . for hurtigt. Derfor er det en god idé at kombinere det her med lidt “repo hygiene”, som jeg vender tilbage til.

3. CI og hosting – secrets der ikke bor i koden

Når det kun er dig og din egen laptop, kan du slippe afsted med ret meget. Når der kommer CI/CD (fx GitHub Actions) og en hostingplatform (Vercel, Netlify, Fly.io, whatever) ind i billedet, skal secrets bo et andet sted end i .env-filer, der ligger og flyder.

GitHub Actions secrets i praksis

Flowet er ret simpelt:

  • Læg secrets ind under Settings → Secrets and variables → Actions
  • Brug dem i workflows som ${{ secrets.MIT_SECRET_NAVN }}

Eksempel på workflow:

name: CI

on: [push]

jobs:
  test:
    runs-on: ubuntu-latest
    env:
      DATABASE_URL: ${{ secrets.DATABASE_URL }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npm test

Bemærk: vi mapper secret ind i env på job-niveau. Det gør det tydeligt, hvilke jobs der faktisk har adgang til hvad. Det passer godt ind i en generel forståelse af deployment og drift, hvor du helst vil kunne se, hvem der rører ved hvad.

Vercel / Netlify / lignende

I hosting-panelet har du typisk tre miljøer: Development, Preview, Production. Brug dem.

  • Prod-nøgler må kun ligge under Production
  • Dev og preview kan bruge test-nøgler

Det vigtige er, at du ikke længere pusher .env til serveren manuelt. Serveren læser fra sine egne secrets, og din CI pusher kun koden.

4. Hvem må se hvad – del op mellem dev og prod

Her går mange små teams forkert: alle har adgang til alt. Det føles nemt i starten, men det gør enhver læk meget værre.

En simpel model, der faktisk kan bruges uden enterprise-adgangskontrol:

  • Dev secrets: alle i dev-teamet må se dem. De er bundet til testmiljøer og falske data.
  • Prod secrets: kun folk der deployer eller drifter systemet til daglig, må have direkte adgang.

Det kan være så lavteknologisk som:

  • En person der opretter prod-nøgler og lægger dem ind i Vercel/Netlify/GitHub
  • En kort intern note: “Prod-keys ligger kun i hosting og Actions, ikke i vores personlige .env”

Og nej, det er ikke perfekt. Men det gør forskel, når nogen får adgang til nogens laptop, eller nogen kommer til at uploade sin egen .env til en bug report.

5. Rotation af secrets – hvornår og uden downtime

Secret rotation lyder meget større end det er. I praksis er det bare: få lavet en ny nøgle, skift den ind, og invalidér den gamle.

Hvornår bør I rotere?

  • Når en person forlader teamet
  • Når en .env-fil er havnet et forkert sted (fx i et delt drive eller en forkert chat)
  • Efter et muligt leak i repoet (mere om det lige om lidt)
  • Som fast rutine, fx hver 3. eller 6. måned for de vigtigste nøgler

Hvordan roterer man uden at vælte alt?

En sikker og nogenlunde smertefri metode:

  1. Opret ny nøgle i den tjeneste du bruger (fx ny API key i Stripe).
  2. Læg både gammel og ny ind som gyldige et kort stykke tid, hvis tjenesten tillader det.
  3. Opdater dine secrets i hosting/CI til at bruge den nye nøgle.
  4. Deploy.
  5. Tjek at alt virker (logins, betalinger, jobs osv.).
  6. Fjern den gamle nøgle hos tredjeparten.

Hvis tjenesten ikke understøtter overlappende nøgler, så planlæg et lille “maintenance” vindue og vær klar til at rulle hurtigt tilbage, hvis noget knækker.

6. Hvis en nøgle er lækket – stop blødningen i 6 trin

På et tidspunkt sker det. En .env i et offentligt repo, en screenshot i et issue, en nøgle postet i den forkerte Slack-kanal. Jeg har selv prøvet det med en test-Stripe nøgle. Det er ikke sjovt, men det er til at overleve, hvis du handler hurtigt.

6-trins “jeg har lige lækket en nøgle” checkliste

  1. Bliv specifik – hvilken nøgle, til hvilken tjeneste, og hvilket miljø (dev/prod)?
  2. Fjern eksponeringen – gør repo privat, slet beskeden, fjern skærmbilledet.
  3. Revokér nøglen i den eksterne tjeneste (Stripe, SendGrid, database osv.).
  4. Opret en ny nøgle og læg den ind de rigtige steder (hosting, CI, lokale .env).
  5. Deploy en version der kører med de nye secrets.
  6. Kig logs igennem for mærkelig aktivitet i tidsrummet mellem læk og rotation.

Det her er også grunden til, at du altid skal kunne rotere hurtigt. Hvis rotation føles som en kæmpe operation, udskyder folk den, og så står man med noget meget værre, hvis nøglen bliver misbrugt.

Hvis du vil øve din evne til at reagere roligt, er det faktisk en fin øvelse at lave et lille test-setup og “lege” læk, mens du holder øje med logs og stacktraces.

7. Scan, tjek og automatisér de kedelige ting

Det sidste lag er automation. Du behøver ikke en kæmpe security-platform for at undgå de værste fejl.

Git-ignore og scanning

Nogle basale ting, som sparker jer ret langt:

  • Sørg for at .env, .env.* og evt. .env.local ligger i .gitignore
  • Brug en pre-commit hook til at stoppe commits med åbenlyse secrets

Eksempel med pre-commit (Python-værktøj, men fungerer fint i JS-projekter):

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/zricethezav/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

Så får du en fejl, inden du overhovedet pusher, hvis du har smidt noget ind der ligner en API-nøgle. Ikke perfekt, men det fanger mange “ups”-øjeblikke.

Audit light – et lille overblik over jeres secrets

Du behøver ikke et stort system for at få et overblik. Et simpelt shared dokument eller README i et privat repo kan faktisk hjælpe meget, hvis I gør det ordentligt:

  • Liste over hvilke secrets der findes (navn og formål, ikke selve værdien)
  • Hvor de er konfigureret (GitHub Actions, Vercel, Netlify osv.)
  • Hvornår de sidst blev roteret, og af hvem

Det gør det meget lettere, når I en dag står med en mistanke om læk og skal tjekke, hvad der overhovedet fandtes. Det passer faktisk rigtig godt ind i samme tankegang som at have styr på projektstruktur og arkitektur: kæden skal kunne følges uden at gætte.

En lille playbook du kan bruge i morgen

Hvis du lige nu tænker “det her er meget fint, men vi har nul tid og tusind andre ting”, så her er den absolut mindste pakke, jeg ville indføre i et lille team:

  • .env lokalt + .env.example i repoet
  • .env i .gitignore + en simpel secret-scanner i pre-commit
  • GitHub Actions secrets i stedet for env-ting hårdkodet i workflows
  • Prod-secrets kun i hosting/CI, aldrig i personlige .env-filer
  • En kort tekstfil med jeres 6-trins “vi har lækket en nøgle” plan

Det er ikke perfekt sikkerhed. Men det flytter jer fra “alt ligger i en zip-fil på skrivebordet” til noget, der faktisk kan holde til, at I bliver flere på holdet.

Jeg opdagede selv hvor skrøbeligt det hele var, da jeg en sen aften fandt en gammel .env i et arkiv på min egen maskine med en produktions-database-url i. Jeg havde glemt, den fandtes. Min kat gik selvfølgelig over tastaturet, mens jeg febrilsk roterede nøgler og fik styr på tingene. Det var der, jeg besluttede, at secrets helst skal være kedelige og meget forudsigelige, ikke noget der først bliver spændende, når alt brænder.

Revoke den kompromitterede nøgle med det samme, opret en ny, og opdater alle steder hvor den bruges (lokale .env, CI-secrets, hosting). Tvangslog ud eller invalider sessioner hvis relevant, kør et hurtigt audit for at se hvem/ hvad der brugte nøglen, og informer berørte parter. Husk at fjerne nøglen fra git-historikken hvis den er committet, og dokumentér proceduren så teamet kan reagere hurtigere næste gang.
Scan historikken med værktøjer som git log/grep, gitleaks, truffleHog eller GitHubs secret scanning for at identificere leaks. Brug BFG eller git filter-repo til at fjerne værdierne fra historikken, force-push den rensede branche, få alle til at klone forfra, og rotér de eksponerede secrets bagefter.
Brug en password manager med team-funktionalitet som Bitwarden eller 1Password til delt adgang og auditing. Kombinér det med platformens secrets (fx GitHub Actions, Vercel) til CI/CD, og undgå at bygge egne u-krypterede delingsløsninger.
Sæt kun ikke-fortrolige variabler som NEXT_PUBLIC_* til klienten. Alt fortroligt logik og nøgler skal ligge på serveren eller i serverless endpoints, og klienten skal kalde disse endpoints eller bruge kortlivede tokens udstedt af backend.

Ida Balslev er den type ven, der pludselig dukker op i din messenger med et link til en lille web-app, hun lige har bygget for sjov – og bagefter gerne viser dig, hvordan du selv kan lave den. Hendes passion for kodning startede med en hjemmebygget hjemmeside til en hestestald og er langsomt vokset gennem aftener med tutorials, fejlmeldinger og små, hjemmelavede projekter.

På Codingclass.dk deler Ida den viden, hun selv manglede i starten: konkrete eksempler, tydelige forklaringer og ærlige historier om, hvad der typisk går galt første, anden og tredje gang. Hun elsker at tage et abstrakt begreb som fx "API" eller "asynkron JavaScript" og koge det ned til noget, du kan se, klikke på og lege med i browseren. For hende handler kodning ikke om at være perfekt, men om at turde prøve, bryde ting og bygge dem op igen.

Ida skriver især om webudvikling med HTML, CSS og JavaScript, små Python-scripts og grundlæggende koncepter som debugging, versionsstyring og struktur i din kode. Hun tænker altid i næste skridt: når du først forstår idéen, viser hun dig, hvordan du kan udvide det med en ekstra funktion, lidt pænere styling eller en smartere måde at tænke din kode på.

Gennem sine artikler på Codingclass.dk vil Ida gerne give dig følelsen af, at du ikke sidder alene med koden – men at der faktisk er en, der har kæmpet med de samme fejlmeddelelser og nu gerne vil vise dig en vej igennem dem, i et tempo hvor alle kan være med.

Send kommentar

You May Have Missed