Skip to content

Secrets Management In Kubernetes

From skillshare session 26/11/2025

Video Recording

How do secrets work in Kubernetes?

  • Kubernetes stores secrets as plain text = compromised cluster = compromised secrets.
  • This is generally fine though: all depends on your threat model.
  • SealedSecrets facilitate a GitOps approach and keep secrets outside of password managers, and inside Git repos - fully encrypted.

Install Bitnami Sealed Secrets

  1. Deploy using ArgoCD:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: sealed-secrets
  namespace: argocd
spec:
  project: default
  source:
    chart: sealed-secrets
    repoURL: https://bitnami-labs.github.io/sealed-secrets
    targetRevision: 2.17.3
    helm:
      releaseName: sealed-secrets-controller
      valuesObject:
        fullnameOverride: sealed-secrets-controller
  destination:
    server: https://kubernetes.default.svc
    namespace: kube-system
  syncPolicy:
    automated:
      selfHeal: true
      prune: true
    syncOptions:
      - CreateNamespace=true
  1. Install kubeseal:
  • Present in ghcr.io/spwoodcock/awscli-kubectl:latest
  • Or install manually: https://github.com/bitnami-labs/sealed-secrets/releases
  1. Backup Sealed Secrets Key:
kubectl get secret -n kube-system -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml >main.key

Store this securely!

Create Sealed Secrets

Using --from-literal (simple values)

kubectl create secret generic cloudflare-api \
    --from-literal=ACCOUNT_ID=your-account-id \
    --from-literal=TOKEN=your-token \
    --dry-run=client \
    --namespace='gateway' \
    -o yaml > secret.yaml

Using --from-file (file contents)

# Single file
kubectl create secret generic my-secret \
    --from-file=config.json \
    --dry-run=client -o yaml > secret.yaml

# Multiple files
kubectl create secret generic tls-secret \
    --from-file=tls.crt \
    --from-file=tls.key \
    --dry-run=client -o yaml > secret.yaml

# Custom key name
kubectl create secret generic my-secret \
    --from-file=my-config=config.json \
    --dry-run=client -o yaml > secret.yaml

Seal and commit

kubeseal -f secret.yaml -w sealed-secret.yaml
rm secret.yaml
git add sealed-secret.yaml

Update Existing Sealed Secret

  1. Get current secret from cluster:
kubectl get secret cloudflare-api -n gateway -o yaml
  1. View current values:
kubectl get secret cloudflare-api -n gateway -o jsonpath='{.data.TOKEN}' | base64 -d
  1. Recreate with new values:
kubectl create secret generic cloudflare-api \
    --from-literal=ACCOUNT_ID=new-account-id \
    --from-literal=TOKEN=new-token \
    --dry-run=client \
    --namespace='gateway' \
    -o yaml > secret.yaml
  1. Re-seal and commit:
kubeseal -f secret.yaml -w sealed-secret.yaml
rm secret.yaml
git add sealed-secret.yaml
git commit -m "Update sealed secret"

Other Options

  • Cloud provider integrations (AWS Secrets Manager, etc.) - not portable
  • External Secrets Operator with Hashicorp Vault - requires external service
  • SealedSecrets = simple, portable, GitOps-friendly