Engineering

Kubernetes Secrets 2026: Complete Guide to Secrets Management and Security

Engineering Team

Kubernetes Secrets store sensitive data like passwords, API keys, and TLS certificates. While convenient, native Secrets require careful handling to maintain security. This comprehensive guide covers Secrets management best practices for production environments in 2026.

Quick Reference: Kubernetes Secrets Commands

CommandDescription
kubectl create secret generic name --from-literal=key=valueCreate from literal
kubectl create secret generic name --from-file=fileCreate from file
kubectl create secret tls name --cert=tls.crt --key=tls.keyCreate TLS secret
kubectl create secret docker-registry name --docker-server=...Create registry secret
kubectl get secretsList secrets
kubectl describe secret nameDescribe secret (hides values)
kubectl get secret name -o jsonpath='{.data.key}' | base64 -dDecode secret value

Understanding Kubernetes Secrets

What Are Secrets?

Secrets are Kubernetes objects that store sensitive data in key-value pairs. They’re similar to ConfigMaps but designed for confidential information.

How Secrets Are Stored

  1. API Server - Receives secret data (base64 encoded)
  2. etcd - Stores secrets (optionally encrypted at rest)
  3. Kubelet - Mounts secrets into pods
  4. Pod - Consumes secrets as env vars or volumes

Secret Types

TypeUse Case
OpaqueGeneral purpose (default)
kubernetes.io/tlsTLS certificates
kubernetes.io/dockerconfigjsonDocker registry credentials
kubernetes.io/service-account-tokenService account tokens
kubernetes.io/basic-authBasic authentication
kubernetes.io/ssh-authSSH credentials

Creating Secrets

From Literal Values

# Create secret with key-value pairs
kubectl create secret generic db-credentials \
  --from-literal=username=admin \
  --from-literal=password='S3cr3tP@ssw0rd!'

# With namespace
kubectl create secret generic db-credentials \
  --from-literal=username=admin \
  --from-literal=password='S3cr3tP@ssw0rd!' \
  -n production

From Files

# Create from files
kubectl create secret generic tls-certs \
  --from-file=tls.crt \
  --from-file=tls.key

# With custom key names
kubectl create secret generic ssh-key \
  --from-file=id_rsa=./ssh/id_rsa \
  --from-file=id_rsa.pub=./ssh/id_rsa.pub

TLS Secrets

kubectl create secret tls my-tls-secret \
  --cert=tls.crt \
  --key=tls.key

Docker Registry Secrets

kubectl create secret docker-registry my-registry \
  --docker-server=https://registry.example.com \
  --docker-username=user \
  --docker-password=password \
  --docker-email=user@example.com

From YAML Manifest

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
  namespace: production
type: Opaque
data:
  # Values must be base64 encoded
  username: YWRtaW4=           # echo -n 'admin' | base64
  password: UzNjcjN0UEBzc3cwcmQh  # echo -n 'S3cr3tP@ssw0rd!' | base64

Using stringData (Plain Text)

apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
type: Opaque
stringData:
  # Plain text - Kubernetes encodes automatically
  username: admin
  password: S3cr3tP@ssw0rd!

Consuming Secrets

As Environment Variables

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: myapp:latest
      env:
        - name: DB_USERNAME
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: username
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: password

All Keys as Environment Variables

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: myapp:latest
      envFrom:
        - secretRef:
            name: db-credentials

As Volume Mount

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
    - name: app
      image: myapp:latest
      volumeMounts:
        - name: secrets-volume
          mountPath: /etc/secrets
          readOnly: true
  volumes:
    - name: secrets-volume
      secret:
        secretName: db-credentials
        defaultMode: 0400  # Read-only for owner

Mount Specific Keys

volumes:
  - name: secrets-volume
    secret:
      secretName: db-credentials
      items:
        - key: password
          path: db-password.txt

For Docker Registry Authentication

apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  imagePullSecrets:
    - name: my-registry
  containers:
    - name: app
      image: registry.example.com/myapp:latest

Encryption at Rest

By default, Secrets are stored unencrypted in etcd. Enable encryption at rest for security.

Configure Encryption

Create encryption config:

# encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <32-byte-base64-encoded-key>
      - identity: {}  # Fallback for reading unencrypted secrets

Generate encryption key:

head -c 32 /dev/urandom | base64

Configure API Server

Add to kube-apiserver:

spec:
  containers:
    - command:
        - kube-apiserver
        - --encryption-provider-config=/etc/kubernetes/encryption-config.yaml

Encrypt Existing Secrets

kubectl get secrets --all-namespaces -o json | kubectl replace -f -

External Secrets Managers

For production, use external secrets managers for enhanced security.

External Secrets Operator (ESO)

Install ESO:

helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespace

AWS Secrets Manager Integration

# SecretStore
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: aws-secrets
  namespace: production
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-east-1
      auth:
        jwt:
          serviceAccountRef:
            name: external-secrets-sa
---
# ExternalSecret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets
    kind: SecretStore
  target:
    name: db-credentials
  data:
    - secretKey: username
      remoteRef:
        key: production/database
        property: username
    - secretKey: password
      remoteRef:
        key: production/database
        property: password

HashiCorp Vault Integration

apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
  name: vault
spec:
  provider:
    vault:
      server: "https://vault.example.com"
      path: "secret"
      version: "v2"
      auth:
        kubernetes:
          mountPath: "kubernetes"
          role: "my-role"
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
spec:
  refreshInterval: 15m
  secretStoreRef:
    name: vault
    kind: SecretStore
  target:
    name: db-credentials
  data:
    - secretKey: password
      remoteRef:
        key: databases/production
        property: password

RBAC for Secrets

Restrict access to secrets with Role-Based Access Control.

Read-Only Access

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: secret-reader
  namespace: production
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get", "list"]
    resourceNames: ["app-secrets"]  # Limit to specific secrets
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-secrets
  namespace: production
subjects:
  - kind: ServiceAccount
    name: app-sa
    namespace: production
roleRef:
  kind: Role
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

Deny Secrets Access

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: no-secrets
  namespace: production
rules:
  - apiGroups: [""]
    resources: ["pods", "services", "deployments"]
    verbs: ["*"]
  # No rules for secrets = no access

Sealed Secrets for GitOps

Encrypt secrets for safe storage in Git.

Install Sealed Secrets

# Install controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml

# Install kubeseal CLI
brew install kubeseal

Create Sealed Secret

# Create regular secret manifest
kubectl create secret generic db-credentials \
  --from-literal=password=mysecret \
  --dry-run=client -o yaml > secret.yaml

# Seal the secret
kubeseal --format yaml < secret.yaml > sealed-secret.yaml

sealed-secret.yaml (safe to commit to Git):

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  encryptedData:
    password: AgBy3i...encrypted...data...
# Apply sealed secret
kubectl apply -f sealed-secret.yaml

Security Best Practices

1. Enable Encryption at Rest

Always encrypt secrets in etcd.

2. Use External Secrets Managers

For production, integrate with Vault, AWS Secrets Manager, or Azure Key Vault.

3. Implement Least Privilege RBAC

# Only allow specific secrets
resourceNames: ["allowed-secret-1", "allowed-secret-2"]

4. Avoid Environment Variables for Sensitive Data

Volume mounts are more secure:

# Better: volume mount
volumeMounts:
  - name: secrets
    mountPath: /etc/secrets
    readOnly: true

# Avoid: environment variable (visible in pod spec)
env:
  - name: PASSWORD
    valueFrom:
      secretKeyRef:
        name: db-credentials
        key: password

5. Rotate Secrets Regularly

# Update secret
kubectl create secret generic db-credentials \
  --from-literal=password=newpassword \
  --dry-run=client -o yaml | kubectl apply -f -

# Restart pods to pick up new secret
kubectl rollout restart deployment/app

6. Audit Secret Access

Enable Kubernetes audit logging:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: Metadata
    resources:
      - group: ""
        resources: ["secrets"]

7. Don’t Log Secrets

# Bad
logger.info(f"Connecting with password: {password}")

# Good
logger.info("Connecting to database...")

8. Use Secret Scanning in CI/CD

Integrate tools like:

  • GitLeaks
  • TruffleHog
  • GitHub Secret Scanning

Complete Example: Secure Application

Secrets

apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
  namespace: production
type: Opaque
stringData:
  db-password: "SecureP@ssword123"
  api-key: "sk-api-key-12345"
---
apiVersion: v1
kind: Secret
metadata:
  name: tls-certs
  namespace: production
type: kubernetes.io/tls
data:
  tls.crt: <base64-encoded-cert>
  tls.key: <base64-encoded-key>

Deployment with Secrets

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      serviceAccountName: api-sa
      containers:
        - name: api
          image: api:v1.0.0
          ports:
            - containerPort: 8080
          volumeMounts:
            - name: secrets
              mountPath: /etc/secrets
              readOnly: true
            - name: tls
              mountPath: /etc/tls
              readOnly: true
      volumes:
        - name: secrets
          secret:
            secretName: app-secrets
            defaultMode: 0400
        - name: tls
          secret:
            secretName: tls-certs
            defaultMode: 0400

Troubleshooting

Secret Not Found

# Check secret exists
kubectl get secret db-credentials -n production

# Check namespace
kubectl get secrets -n production

Permission Denied

# Check RBAC
kubectl auth can-i get secrets -n production --as system:serviceaccount:production:app-sa

Decode Secret Value

kubectl get secret db-credentials -o jsonpath='{.data.password}' | base64 -d

Secret Not Updating in Pod

Secrets mounted as volumes update automatically (~1 min). Secrets as env vars require pod restart:

kubectl rollout restart deployment/app

Conclusion

Kubernetes Secrets require careful management for security in 2026. Key takeaways:

  • Enable encryption at rest for etcd
  • Use external secrets managers for production
  • Implement RBAC with least privilege
  • Prefer volume mounts over environment variables
  • Use Sealed Secrets for GitOps
  • Rotate secrets regularly
  • Audit secret access

Master Secrets management to build secure Kubernetes applications.


Need help with Kubernetes security? Book a free 30-minute consultation with our security experts.

Chat with real humans
Chat on WhatsApp