🟡 Intermediate

Secrets Management — Bezpečná správa tajomstiev

Prečo je secrets management dôležitý

Každá aplikácia potrebuje tajomstvá — API kľúče, databázové heslá, TLS certifikáty, tokeny tretích strán. Spôsob, akým s nimi nakladáme, priamo ovplyvňuje bezpečnosť celej infraštruktúry.

Typické problémy bez správneho secrets managementu:

  • Heslá commitnuté v Git repozitári (aj po zmazaní zostávajú v histórii)
  • Zdieľané .env súbory posielané cez Slack alebo email
  • Rovnaké heslo používané naprieč prostrediami (dev / staging / prod)
  • Žiadna rotácia — rovnaké credentials mesiace alebo roky
  • Žiadny audit trail — nevieme kto, kedy a čo čítal

Dôsledky úniku:

  • Kompromitácia databáz a služieb
  • Finančné straty (zneužitie cloud API kľúčov)
  • Regulačné pokuty (GDPR, PCI-DSS)
  • Strata dôvery zákazníkov

HashiCorp Vault

Vault je najrozšírenejší open-source nástroj na centralizovanú správu tajomstiev.

Architektúra

┌─────────────────────────────────────┐
│             Vault Server            │
│  ┌───────────┐  ┌────────────────┐  │
│  │  Storage   │  │ Secret Engines │  │
│  │  Backend   │  │  (KV, PKI,    │  │
│  │ (Consul,   │  │   Database,   │  │
│  │  Raft,     │  │   Transit)    │  │
│  │  S3...)    │  └────────────────┘  │
│  └───────────┘  ┌────────────────┐  │
│  ┌───────────┐  │    Policies    │  │
│  │   Auth     │  │  (ACL, RBAC)  │  │
│  │  Methods   │  └────────────────┘  │
│  └───────────┘                       │
└─────────────────────────────────────┘
        ▲              ▲
        │              │
   ┌────┴───┐    ┌─────┴─────┐
   │  CLI   │    │  API/SDK  │
   └────────┘    └───────────┘

Seal / Unseal

Vault sa po štarte nachádza v sealed stave — dáta sú zašifrované a neprístupné. Na unseal je potrebných N z M kľúčov (Shamir's Secret Sharing):

# Inicializácia — vygeneruje unseal kľúče a root token
vault operator init -key-shares=5 -key-threshold=3

# Unseal — treba opakovať 3× s rôznymi kľúčmi
vault operator unseal <key-1>
vault operator unseal <key-2>
vault operator unseal <key-3>

# Auto-unseal cez cloud KMS (produkčné prostredie)
seal "awskms" {
  region     = "eu-central-1"
  kms_key_id = "alias/vault-unseal"
}

Secret Engines

Engine Použitie
KV v2 Key-value úložisko s verzovaním
Database Dynamické credentials pre PostgreSQL, MySQL, MongoDB
PKI Generovanie TLS certifikátov
Transit Encryption as a Service (šifrovanie bez odhalenia kľúča)
AWS/Azure/GCP Dynamické cloud credentials
# KV secret engine
vault secrets enable -path=secret kv-v2
vault kv put secret/myapp db_password="S3cur3P@ss!"
vault kv get secret/myapp

# Dynamické DB credentials
vault secrets enable database
vault write database/config/mydb \
  plugin_name=postgresql-database-plugin \
  connection_url="postgresql://{{username}}:{{password}}@db:5432/mydb" \
  allowed_roles="readonly"

vault write database/roles/readonly \
  db_name=mydb \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
  default_ttl="1h" \
  max_ttl="24h"

# Aplikácia si vyžiada credentials
vault read database/creds/readonly
# → username: v-token-readonly-abc123
# → password: A1b2C3d4E5f6
# → TTL: 1h (automaticky expiruje)

Policies

# policy: app-readonly.hcl
path "secret/data/myapp/*" {
  capabilities = ["read", "list"]
}

path "database/creds/readonly" {
  capabilities = ["read"]
}

# Deny explicitne
path "secret/data/admin/*" {
  capabilities = ["deny"]
}
vault policy write app-readonly app-readonly.hcl
vault token create -policy="app-readonly"

SOPS (Mozilla) — Encrypted files in Git

SOPS (Secrets OPerationS) šifruje hodnoty v YAML/JSON/ENV súboroch, pričom kľúče zostávajú čitateľné. Ideálne pre GitOps workflow.

Ako to funguje

# Pred šifrovaním (secrets.yaml)
db:
  password: SuperSecret123
  host: db.example.com

# Po šifrovaní (secrets.enc.yaml)
db:
  password: ENC[AES256_GCM,data:abc123...,iv:...,tag:...]
  host: db.example.com    # nešifrované — vidíme štruktúru
sops:
  kms:
    - arn: arn:aws:kms:eu-central-1:123456:key/abc-def
  version: 3.7.3

Použitie

# Šifrovanie s AWS KMS
sops --encrypt --kms "arn:aws:kms:eu-central-1:123:key/abc" \
  secrets.yaml > secrets.enc.yaml

# Šifrovanie s AGE (lokálne, bez cloudu)
age-keygen -o keys.txt
export SOPS_AGE_KEY_FILE=keys.txt
sops --encrypt --age "age1..." secrets.yaml > secrets.enc.yaml

# Dešifrovanie
sops --decrypt secrets.enc.yaml

# Editácia — otvorí dešifrovaný súbor v $EDITOR
sops secrets.enc.yaml

# Integrácia s Helm
helm secrets upgrade myapp ./chart -f secrets.enc.yaml

Výhody SOPS

  • Šifrované súbory žijú priamo v Git repozitári
  • Code review funguje — vidíme aké kľúče sa menili
  • Podpora viacerých KMS providerov (AWS, GCP, Azure, AGE, PGP)
  • Jednoduchá integrácia s CI/CD a Helm

Kubernetes Sealed Secrets

Sealed Secrets od Bitnami riešia problém ukladania Kubernetes Secrets do Gitu.

Princíp

┌──────────────┐    kubeseal     ┌──────────────────┐
│  Secret      │ ──────────────► │  SealedSecret    │
│  (plaintext) │   (asymetrické  │  (šifrované,     │
│              │    šifrovanie)   │   safe for Git)  │
└──────────────┘                 └──────────────────┘
                                         │
                                    git push
                                         │
                                         ▼
                                 ┌──────────────────┐
                                 │ Sealed Secrets   │
                                 │ Controller       │
                                 │ (v klastri)      │
                                 │  → dešifruje     │
                                 │  → vytvorí Secret│
                                 └──────────────────┘

Použitie

# Inštalácia controllera
helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
helm install sealed-secrets sealed-secrets/sealed-secrets -n kube-system

# Vytvorenie SealedSecret
kubectl create secret generic myapp-secret \
  --from-literal=password=S3cret! \
  --dry-run=client -o yaml | \
  kubeseal --format yaml > myapp-sealed-secret.yaml

# Aplikovanie — controller dešifruje a vytvorí Secret
kubectl apply -f myapp-sealed-secret.yaml

AWS Secrets Manager / Parameter Store

AWS ponúka dva natívne služby na správu tajomstiev.

Secrets Manager

Plnohodnotný secrets management s automatickou rotáciou:

# Vytvorenie secretu
aws secretsmanager create-secret \
  --name "prod/myapp/db" \
  --secret-string '{"username":"admin","password":"S3cur3!"}'

# Čítanie
aws secretsmanager get-secret-value --secret-id "prod/myapp/db"

# Automatická rotácia cez Lambda
aws secretsmanager rotate-secret \
  --secret-id "prod/myapp/db" \
  --rotation-lambda-arn arn:aws:lambda:...:function:rotate-db \
  --rotation-rules '{"AutomaticallyAfterDays": 30}'

Parameter Store (SSM)

Jednoduchšie a lacnejšie riešenie pre konfiguráciu a secrets:

# SecureString — šifrované cez KMS
aws ssm put-parameter \
  --name "/prod/myapp/db_password" \
  --type SecureString \
  --value "S3cur3P@ss!"

# Čítanie
aws ssm get-parameter \
  --name "/prod/myapp/db_password" \
  --with-decryption

# Hierarchické čítanie
aws ssm get-parameters-by-path \
  --path "/prod/myapp/" \
  --with-decryption

Porovnanie

Vlastnosť Secrets Manager Parameter Store
Cena ~$0.40/secret/mesiac Free tier (Standard)
Rotácia Natívna (Lambda) Manuálna
Cross-account Áno (resource policy) Obmedzená
Verzovanie Áno Áno
Veľkosť 64 KB 8 KB (Standard)

Environment variables vs Secrets managers

Environment variables — riziká

# Typický anti-pattern
export DB_PASSWORD="SuperSecret123"
docker run -e DB_PASSWORD=$DB_PASSWORD myapp

# Problémy:
# 1. Viditeľné cez /proc/<pid>/environ
# 2. Logované v shell history
# 3. Zdedené child procesmi
# 4. Viditeľné v docker inspect

Secrets manager prístup

# Python — čítanie z Vault za behu
import hvac

client = hvac.Client(url='https://vault.example.com')
client.auth.kubernetes.login(role='myapp', jwt=sa_token)

secret = client.secrets.kv.v2.read_secret_version(
    path='myapp',
    mount_point='secret'
)
db_password = secret['data']['data']['db_password']
# Kubernetes — Vault Agent Injector
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    metadata:
      annotations:
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/role: "myapp"
        vault.hashicorp.com/agent-inject-secret-db: "secret/data/myapp"
    spec:
      containers:
        - name: myapp
          # Secret sa objaví ako súbor /vault/secrets/db

Kedy sú env vars akceptovateľné

  • Lokálny vývoj (s .env v .gitignore)
  • CI/CD pipeline premenné (GitHub Actions Secrets, GitLab CI Variables)
  • Kombinácia: env var obsahuje cestu k secretu, nie secret samotný

Secret Rotation

Pravidelná rotácia minimalizuje dopad prípadného úniku.

Stratégie rotácie

1. Automatická rotácia (ideálne)

# AWS Secrets Manager — každých 30 dní
aws secretsmanager rotate-secret \
  --secret-id "prod/db" \
  --rotation-rules '{"AutomaticallyAfterDays": 30}'

# Vault — dynamické credentials s TTL
vault write database/roles/app \
  default_ttl="1h" max_ttl="24h"
# Credentials automaticky expirujú, aplikácia si vyžiada nové

2. Dual-secret rotácia (zero-downtime)

Fáza 1: Vytvor nový secret (v2), starý (v1) stále funguje
Fáza 2: Aktualizuj aplikácie na v2
Fáza 3: Zruš platnosť v1

3. Rotačný checklist

  • Databázové heslá — každých 30-90 dní
  • API kľúče — každých 90 dní
  • TLS certifikáty — pred expiráciou (cert-manager automatizuje)
  • SSH kľúče — každých 6-12 mesiacov
  • Service account tokeny — krátkodobé (1h), automaticky obnovované

Best Practices

1. Least Privilege

# Vault policy — len čo aplikácia naozaj potrebuje
path "secret/data/myapp/db" {
  capabilities = ["read"]
}
# NIE: path "secret/*" { capabilities = ["read", "list", "create"] }

2. Audit logging

# Vault audit log
vault audit enable file file_path=/var/log/vault-audit.log

# Každý prístup je zaznamenaný:
# {
#   "auth": {"token_type": "service", "policies": ["app-readonly"]},
#   "request": {"path": "secret/data/myapp", "operation": "read"},
#   "response": {"data": {"keys": ["password"]}}
# }

3. Encryption at rest & in transit

  • Secrets vždy šifrované na disku (AES-256)
  • Komunikácia cez TLS (mTLS pre service-to-service)
  • Vault Transit engine na šifrovanie aplikačných dát

4. Žiadne secrets v kóde

# Pre-commit hook — detekcia secrets
pip install detect-secrets
detect-secrets scan --all-files --baseline .secrets.baseline

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.4.0
    hooks:
      - id: detect-secrets
        args: ['--baseline', '.secrets.baseline']

5. Disaster recovery

  • Zálohovanie Vault dát a unseal kľúčov (offline, šifrované)
  • Testovanie obnovy zo zálohy
  • Dokumentovaný incident response plán pre únik secrets

Porovnávacia tabuľka nástrojov

Nástroj Typ Rotácia Git-friendly Dynamické credentials Cena
HashiCorp Vault Centralizovaný server ✅ Automatická ❌ (agent/API) ✅ (DB, Cloud, PKI) Open-source / Enterprise
SOPS Šifrované súbory ❌ Manuálna ✅ Natívne Free (OSS)
Sealed Secrets K8s controller ❌ Manuálna ✅ (SealedSecret) Free (OSS)
AWS Secrets Manager Managed služba ✅ Lambda rotácia ~$0.40/secret/mes
AWS Parameter Store Managed služba ❌ Manuálna Free (Standard)
Azure Key Vault Managed služba Pay-per-use
GCP Secret Manager Managed služba ~$0.06/10k operácií
CyberArk Conjur Enterprise server Enterprise licencia
Doppler SaaS Free tier / Paid

Kedy čo použiť

  • Malý tím, GitOps → SOPS + AGE
  • Kubernetes → Sealed Secrets + External Secrets Operator
  • Enterprise / multi-cloud → HashiCorp Vault
  • Čisto AWS → Secrets Manager + Parameter Store
  • Rýchly štart → Doppler alebo cloud-natívne riešenie

Zhrnutie

Secrets management nie je luxus — je to základ bezpečnej infraštruktúry. Kľúčové princípy:

  1. Nikdy necommituj secrets do Gitu v plaintext forme
  2. Centralizuj správu secrets (Vault, cloud manager)
  3. Rotuj pravidelne a automaticky kde sa dá
  4. Audituj každý prístup k tajomstvám
  5. Least privilege — každý komponent dostane len to, čo potrebuje
  6. Šifruj at rest aj in transit
  7. Detekuj náhodné úniky (pre-commit hooks, secret scanning)