Intensiv DevOps-uddannelse · Lektion

Sikker håndtering af hemmeligheder og rent miljø

Hold legitimationsoplysninger ude af proceslister og logs ved hjælp af stdin, filer og rensede miljøer.

Lektion 2 af 413 trin

Sikker håndtering af hemmeligheder og rent miljø er en gratis Intensiv DevOps-uddannelse-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Intensiv DevOps-uddannelse, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Intensiv DevOps-uddannelse-kurset indeholder 4 lektioner i alt.

Hvorfor god håndtering af hemmeligheder er vigtig

Hemmeligheder — API-nøgler, adgangskoder og tokens — er de mest følsomme data i ethvert system. Forkert håndtering af dem i Bash-scripts er en af de mest almindelige og skadelige sikkerhedsfejl.

  • Proceslister: Argumenter, der sendes til kommandoer, vises i ps aux, /proc/<pid>/cmdline og systemets revisionslogge — synlige for alle brugere på værten.
  • Shell-historik: Kommandoer, der indtastes interaktivt (og nogle gange scripts), gemmes i ~/.bash_history.
  • Logfiler: Spor fra set -x, applikationslogge og CI/CD-output kan opfange variableværdier.
  • Lækage gennem miljøet: Underprocesser arver hele deres overordnede proces' miljø, herunder alle eksporterede hemmeligheder.

Et hærdet script behandler hemmeligheder som radioaktivt materiale — minimér eksponeringstiden, begræns overfladen, og rens alt på vej ud.

Angrebsfladen i proceslister

Når du sender en hemmelighed som et kommandolinjeargument, kan alle brugere på systemet straks læse den via ps. Det er ikke teoretisk — det udnyttes jævnligt i delte hostingmiljøer og container-miljøer.

Uddraget nedenfor viser problemet og løsningen side om side.

#!/usr/bin/env bash
# DANGEROUS: password visible in 'ps aux' output
# curl -u "admin:SuperSecret123" https://api.example.com/data

# SAFE: pass credentials via stdin or a flag that reads from a file
# Many tools support reading secrets from stdin with '-' or dedicated flags:

# Option 1 — pipe the secret so it never appears in argv
echo 'SuperSecret123' | curl -u 'admin' --password-stdin \
  https://api.example.com/data 2>/dev/null || true

# Option 2 — write a temporary netrc and point curl at it
# (covered in a later scene)
echo 'Secret never touches the command line this way'

Læsning af hemmeligheder fra stdin

Det sikreste interaktive mønster er at læse en hemmelighed under kørsel med read -rs. Flaget -s undertrykker ekko, så tegnene aldrig vises, og -r forhindrer fortolkning af omvendte skråstreger.

Vigtige punkter:

  • Variablen eksporteres aldrig, så underprocesser ikke kan se den via /proc/<pid>/environ.
  • Efter brug skal du straks unset variablen for at forkorte eksponeringsvinduet.
  • Undgå echo "$SECRET" — brug printf '%s' for at forhindre, at et afsluttende linjeskift ødelægger værdien, og for at forblive usynlig i sporingsoutput.
#!/usr/bin/env bash
set -euo pipefail

# Prompt on stderr so stdout stays clean for piping
read -rsp 'Enter API token: ' API_TOKEN <&2
printf '\n' >&2

# Use the secret — printf keeps it out of argv
response=$(printf '%s' "$API_TOKEN" | curl -sS -X POST \
  -H 'Content-Type: application/json' \
  --data-binary @- \
  https://httpbin.org/post 2>/dev/null) || true

echo "Request sent."

# Scrub immediately — unset removes it from shell memory
unset API_TOKEN

Hemmeligheder i filer: Tilladelser og ejerskab

Når en hemmelighed skal gemmes på disken (f.eks. en nøgle til en servicekonto), er filens tilladelser dit primære forsvar.

  • Tilstand 0600 — kan kun læses og skrives af ejeren. Ingen adgang for gruppen eller andre.
  • Tilstand 0400 — skrivebeskyttet for ejeren. Foretræk dette til nøgler, som du aldrig ved et uheld bør overskrive.
  • Gem hemmelighedsfiler i en dedikeret mappe som ~/.secrets/ eller /run/secrets/ (sidstnævnte er et RAM-baseret tmpfs på mange Linux-systemer og findes kun indtil næste genstart).
  • Placér aldrig hemmelighedsfiler i en git-sporet mappe uden en helt solid .gitignore.
#!/usr/bin/env bash
set -euo pipefail

SECRETS_DIR="${HOME}/.secrets"
mkdir -p "$SECRETS_DIR"
chmod 700 "$SECRETS_DIR"   # directory: only owner can list contents

KEY_FILE="${SECRETS_DIR}/api_token"

# Write secret — atomically restrict permissions before writing content
install -m 0600 /dev/null "$KEY_FILE"
printf '%s' 'my-super-secret-token' > "$KEY_FILE"

echo "Permissions:"
ls -la "$KEY_FILE"

# Read back safely — no subshell, no echo
API_TOKEN=$(< "$KEY_FILE")
echo "Token length: ${#API_TOKEN} chars (value not printed)"
unset API_TOKEN

Brug af en .netrc-fil med curl

curl understøtter en ~/.netrc-fil (eller en vilkårlig sti via --netrc-file), der knytter værtsnavne til legitimationsoplysninger. Det holder godkendelsesdata helt væk fra kommandolinjen og scriptets brødtekst.

Filformatet er enkelt:

machine api.example.com
  login admin
  password s3cr3t

Bedste praksis:

  • Sæt altid chmod 0600 ~/.netrc — curl afviser filen, hvis den kan læses af alle, på nogle systemer.
  • Brug --netrc-file /run/secrets/netrc til at pege på en hemmelighed i et tmpfs eller en hemmelighed, der er tilført containeren.
  • Ryd midlertidige netrc-filer op med en trap ved EXIT.
#!/usr/bin/env bash
set -euo pipefail

TMP_NETRC=$(mktemp)
chmod 0600 "$TMP_NETRC"

# Trap ensures cleanup even on error or signal
trap 'rm -f "$TMP_NETRC"' EXIT

# Write credentials to the temp netrc
cat > "$TMP_NETRC" <<'EOF'
machine httpbin.org
  login myuser
  password mypassword
EOF

curl -fsS --netrc-file "$TMP_NETRC" \
  https://httpbin.org/basic-auth/myuser/mypassword \
  -o /dev/null -w 'HTTP %{http_code}\n' || true

# trap fires here: $TMP_NETRC is deleted
echo 'Temp netrc cleaned up by trap.'

Hygiejne for miljøvariabler

Miljøvariabler er en populær måde at tilføre hemmeligheder til scripts på (12-factor-apps, CI/CD-pipelines). De lækkes dog til hver underproces og findes i /proc/<pid>/environ i hele processens levetid.

Beskyttende mønstre:

  • Indlæs straks hemmeligheden i en lokal variabel, og fjern miljøvariablen med unset, så underprocesser ikke kan arve den.
  • Send hemmeligheder til bestemte kommandoer med env -i eller en tildeling på samme linje i stedet for at bruge hele det nedarvede miljø.
  • Brug aldrig export med en hemmelighedsvariabel — brug om muligt kun en tildeling (uden export).
#!/usr/bin/env bash
set -euo pipefail

# Simulate a secret arriving via environment (e.g., from CI system)
export DB_PASSWORD='hunter2'   # set by CI — we did not choose this

# Capture locally, then strip from environment immediately
db_password="$DB_PASSWORD"
unset DB_PASSWORD

# Verify the env var is gone before spawning any child process
if printenv DB_PASSWORD 2>/dev/null; then
  echo 'ERROR: DB_PASSWORD still in environment!' >&2
  exit 1
fi

echo 'Secret captured and env var scrubbed.'
echo "Password length: ${#db_password}"
unset db_password

Forhindring af, at hemmeligheder vises i spor fra set -x

set -x (xtrace) er uvurderlig til fejlfinding, men udskriver værdien af hver variabel, den udvider — også hemmeligheder — til stderr. Disse spor ender ofte i CI-logfiler eller syslog.

Strategier til at beskytte hemmeligheder og samtidig bevare nyttig sporing:

  • Deaktivér sporing midlertidigt omkring følsomme handlinger med { set +x; } 2>/dev/null.
  • Aktivér den igen bagefter med set -x.
  • Omdirigér xtrace-outputtet til en separat fildeskriptor, der skriver til en beskyttet logfil i stedet for den offentlige logstrøm.
#!/usr/bin/env bash
set -euo pipefail
set -x   # tracing ON — safe for non-sensitive sections

echo 'Building application...'
SRC_DIR='/tmp/build'
mkdir -p "$SRC_DIR"

# Disable xtrace around secret handling (suppress the set +x line itself)
{ set +x; } 2>/dev/null

read -rsp 'Token (hidden from trace): ' SECRET_TOKEN <&2
printf '\n' >&2
token_len=${#SECRET_TOKEN}
unset SECRET_TOKEN

set -x  # tracing back ON

echo "Token captured (length=$token_len). Continuing build..."
ls "$SRC_DIR"

Fjernelse af hemmeligheder fra logfiler

Selv når du er forsigtig, finder hemmeligheder nogle gange vej til logoutputtet — især i udførlige eller ældre scripts. En wrapperfunktion til logning, der slører kendte mønstre, giver et ekstra sikkerhedsnet.

Dette mønster bruger en regex-baseret erstatning på alt logoutput. Det er et sidste forsvarslag og ikke en erstatning for de øvrige hygiejnepraksisser, der allerede er gennemgået.

#!/usr/bin/env bash
set -euo pipefail

# A logging function that scrubs common secret patterns before writing
log() {
  local line
  # Replace anything that looks like key=VALUE or password=VALUE
  line=$(printf '%s\n' "$*" \
    | sed -E 's/(password|token|secret|key)=[^[:space:]]*/\1=***REDACTED***/gi')
  printf '[%s] %s\n' "$(date -u '+%T')" "$line"
}

# Usage:
log 'Connecting to database with password=hunter2'
log 'Loaded API token=sk-abc123xyz secret'
log 'Build step completed successfully'   # unchanged

Isolerede miljøer med env -i

env -i starter en kommando med et helt tomt miljø, så ingen nedarvede variabler — herunder utilsigtede hemmeligheder — når frem til underprocessen. Derefter sender du eksplicit kun det, der er nødvendigt.

Det er især nyttigt, når du kører scripts, buildværktøjer eller tredjepartsværktøjer, som ikke er pålidelige og kan forsøge at hente data ud af miljøet.

#!/usr/bin/env bash
set -euo pipefail

# Polluted parent environment (simulating a CI runner)
export AWS_SECRET_ACCESS_KEY='AKIAIOSFODNN7EXAMPLE'
export GITHUB_TOKEN='ghp_faketoken123'
export HOME="$HOME"
export PATH="$PATH"

echo '--- Child sees full environment:'
env | grep -E 'AWS|GITHUB' | head -5

echo '--- Sanitised child (env -i) sees nothing secret:'
env -i HOME="$HOME" PATH="$PATH" TERM="${TERM:-dumb}" \
  bash -c 'env | grep -E "AWS|GITHUB" || echo "No secrets visible"'

unset AWS_SECRET_ACCESS_KEY GITHUB_TOKEN

Midlertidige hemmelighedsfiler på tmpfs

tmpfs er et RAM-baseret filsystem. Filer, der skrives dertil, tømmes aldrig til disken, hvilket fjerner risikoen for, at hemmeligheder overlever i swap, diskcache eller snapshots.

  • På Linux er /dev/shm og /run/user/<uid> typisk tmpfs-monteringer.
  • Kombinér altid brug af tmpfs med en trap EXIT for at slette filer, når scriptet afsluttes.
  • I containere (Docker, Kubernetes) kan hemmeligheder monteres som tmpfs-diskenheder direkte i /run/secrets.
#!/usr/bin/env bash
set -euo pipefail

# Prefer /run/user/$UID (user-owned tmpfs) or /dev/shm (world-readable dir!)
if [[ -d "/run/user/$UID" ]]; then
  TMPFS_DIR="/run/user/$UID"
elif [[ -d '/dev/shm' ]]; then
  TMPFS_DIR='/dev/shm'
else
  # Fallback: warn that disk will be used
  echo 'WARNING: No tmpfs available; using /tmp (disk-backed)' >&2
  TMPFS_DIR='/tmp'
fi

SECRET_FILE=$(mktemp "${TMPFS_DIR}/secret.XXXXXX")
chmod 0600 "$SECRET_FILE"
trap 'shred -u "$SECRET_FILE" 2>/dev/null || rm -f "$SECRET_FILE"' EXIT

printf '%s' 'my-runtime-token' > "$SECRET_FILE"
echo "Secret stored in: $SECRET_FILE"
df -T "$SECRET_FILE" | awk 'NR==2 {print "Filesystem type:", $2}'

# Use the secret...
token=$(< "$SECRET_FILE")
echo "Token length: ${#token}"
unset token
# trap fires on exit: file shredded

Sådan samles det hele: Et hærdet deploymentscript

Det følgende script kombinerer alle teknikkerne fra denne lektion i en realistisk hjælper til deployment. Læg mærke til, hvordan hvert forsvarslag styrker de andre:

  • Læsning fra stdin med -s — ingen ekko på terminalen
  • Hemmelighedsfil på tmpfs med oprydning via trap
  • Rensning af miljøet — hemmeligheden fjernes med unset før enhver underproces
  • xtrace-vagt — sporing sættes på pause omkring følsom kode
  • Sløring i loggen — sikkerhedsnet med regex før skrivning til loggen
#!/usr/bin/env bash
set -euo pipefail

### 1. Redacting logger
log() {
  local msg
  msg=$(printf '%s' "$*" \
    | sed -E 's/(password|token|secret|key)=[^[:space:]]*/\1=***/gi')
  printf '[%s] %s\n' "$(date -u +%T)" "$msg"
}

### 2. tmpfs secret store
TMPFS_DIR="${XDG_RUNTIME_DIR:-/tmp}"
SECRET_FILE=$(mktemp "${TMPFS_DIR}/deploy_token.XXXXXX")
chmod 0600 "$SECRET_FILE"
trap 'rm -f "$SECRET_FILE"; log "Secret file cleaned up."' EXIT

### 3. Read secret without trace
{ set +x; } 2>/dev/null
read -rsp 'Deploy token: ' _tok <&2; printf '\n' >&2
printf '%s' "$_tok" > "$SECRET_FILE"
unset _tok
set -x

### 4. Scrub inherited env vars before subprocess
unset DEPLOY_TOKEN 2>/dev/null || true

log 'Starting deployment...'
# Simulate deploy using secret from file (token never in argv)
# curl -H "Authorization: Bearer $(< $SECRET_FILE)" https://api.example.com/deploy
log 'Deployment complete. token=hidden_by_redactor'

echo 'Done.'

Videnstjek: Eksponering af hemmeligheder via procesliste

Test din forståelse af, hvordan hemmeligheder lækkes gennem proceslister, og hvordan du kan forhindre det.

Opsummering af lektionen: Sikker håndtering af hemmeligheder

Du har gennemført Sikker håndtering af hemmeligheder og miljøhygiejne. Her er en kort oversigt over alt det, der blev gennemgået:

  • Proceslister: Send aldrig hemmeligheder som kommandolinjeargumenter — de vises i ps aux og /proc/<pid>/cmdline. Brug i stedet piping via stdin eller --netrc-file.
  • Læsning fra stdin: Brug read -rs til interaktivt at indsamle hemmeligheder uden ekko på terminalen eller eksponering i shellhistorikken.
  • Filtilladelser: Hemmelighedsfiler skal have chmod 0600 (eller 0400). Brug install -m 0600 til atomisk oprettelse.
  • netrc-filer: Overlad legitimationsoplysninger til en midlertidig fil, som der peges på med --netrc-file; ryd op med trap EXIT.
  • Miljøhygiejne: Fjern straks hemmelige miljøvariabler med unset, efter at du har gemt dem lokalt; brug aldrig export unødvendigt; brug env -i til isolering af underprocesser.
  • xtrace-vagt: Omslut følsom kode med { set +x; } 2>/dev/null ... set -x for at forhindre, at fejlfindingsspor lækker værdier.
  • Sløring i loggen: Brug en logger baseret på sed som sidste sikkerhedsnet.
  • tmpfs: Gem runtime-hemmeligheder i /run/user/$UID eller /dev/shm, så de aldrig rammer disken; makulér dem ved afslutning.

Forsvar i dybden er den afgørende tankegang: Ingen enkelt foranstaltning er tilstrækkelig, men når du kombinerer dem i lag, bliver lækage af hemmeligheder ekstremt vanskelig.

Gratis at komme i gang

Lær Intensiv DevOps-uddannelse med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
142
Lektioner
568

Ofte stillede spørgsmål

Er lektionen “Sikker håndtering af hemmeligheder og rent miljø” gratis?

Ja — alle 3 lektioner i læringssporet Intensiv DevOps-uddannelse, inklusive “Sikker håndtering af hemmeligheder og rent miljø”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Intensiv DevOps-uddannelse-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Sikker håndtering af hemmeligheder og rent miljø”?

Hold legitimationsoplysninger ude af proceslister og logs ved hjælp af stdin, filer og rensede miljøer. Du øver dig i Intensiv DevOps-uddannelse med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Intensiv DevOps-uddannelse?

Der kræves ingen tidligere erfaring. Intensiv DevOps-uddannelse på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.

Hvor lang tid tager lektionen “Sikker håndtering af hemmeligheder og rent miljø”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Intensiv DevOps-uddannelse-lektion?

Ja. Alle Intensiv DevOps-uddannelse-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Forebyggelse af kommando- og argumentinjektion
  2. Sikker håndtering af hemmeligheder og rent miljø
  3. Kørsel med færrest mulige rettigheder og disciplineret brug af sudo
  4. Statisk analyse og audit med ShellCheck
← Tilbage til Intensiv DevOps-uddannelse