Secrets management w Kubernetes — Sealed Secrets vs External Secrets Operator
Jak bezpiecznie trzymać sekrety w repozytorium GitOps? Porównuję dwa podejścia: Sealed Secrets (szyfrowanie w repo) i External Secrets Operator (sekrety w zewnętrznym vault).
Problem: sekrety w GitOps
GitOps zakłada, że wszystko jest w repozytorium Git. Ale sekrety (hasła do baz, klucze API) nie mogą być w repo jako plain text.
Naiwne rozwiązanie — placeholder w repo, ręczny kubectl apply dla sekretów — psuje GitOps: ArgoCD nie zarządza sekretami, trzeba pamiętać o ręcznym tworzeniu.
Opcja 1: Sealed Secrets
Sealed Secrets to operator K8s, który umożliwia zaszyfrowanie sekretu kluczem publicznym klastra. Zaszyfrowany sekret (SealedSecret) można bezpiecznie commitować do repo.
# Instalacja
helm install sealed-secrets sealed-secrets/sealed-secrets -n kube-system
# Szyfrowanie sekretu
kubectl create secret generic db-password
--from-literal=password=supersecret
--dry-run=client -o yaml |
kubeseal --format yaml > k8s/sealed-db-password.yaml
Wynikowy SealedSecret jest bezużyteczny bez klucza prywatnego klastra:
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: db-password
spec:
encryptedData:
password: AgBY3mT....(długi zaszyfrowany ciąg)....
Zalety: proste, działa offline, sekrety w repo razem z manifestami Wady: rotacja kluczy klastra wymaga re-szyfrowania wszystkich sekretów, trudniejsze audytowanie
Opcja 2: External Secrets Operator (ESO)
ESO synchronizuje sekrety z zewnętrznego vault (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager) do Kubernetes Secrets.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-store
kind: ClusterSecretStore
target:
name: db-credentials
data:
- secretKey: password
remoteRef:
key: portfolio/db
property: password
Zalety: centralne zarządzanie sekretami, audyt dostępu, rotacja bez zmian w K8s Wady: zewnętrzna zależność, więcej do konfigurowania
Co wybrałem?
Na środowisku deweloperskim (Minikube) używam plain kubectl create secret — bez GitOps dla sekretów.
Na produkcji planuję Sealed Secrets — prostsze i samodzielne, bez potrzeby zewnętrznego vault. Jeśli projekt wyrośnie i trafi do chmury, migracja do ESO + AWS Secrets Manager będzie naturalnym krokiem.
Secrets w CI/CD
Sekrety używane w GitHub Actions (hasła do GHCR, deploy keys) trzymam w GitHub Secrets — zarządzane przez GitHub, odizolowane od kodu:
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} # Automatycznie dostępny
GITHUB_TOKEN jest generowany automatycznie per job — nie trzeba go nigdzie przechowywać.