By default, Kubernetes Secrets are stored in Base64-encoded format inside etcd (the cluster’s key-value store). While this isn’t encryption, it prevents sensitive values from being exposed as plain text in configuration files. However, additional security measures are required to properly protect Secrets.

Why Use a Secret Instead of a ConfigMap?

Using Secrets instead of ConfigMaps offers several benefits:

  • Prevents storing sensitive data in container images – Secrets can be mounted at runtime instead of being hardcoded in the application.
  • Reduces exposure risks – Secrets are not visible in environment variables by default, reducing the risk of accidental leaks.
  • Supports encrypted storage – When configured properly, Kubernetes Secrets can be encrypted at rest.
  • Tighter access control – You can use RBAC (Role-Based Access Control) to restrict access to specific users and pods.

How Does it Work?

A Secret in Kubernetes can store:

  • Opaque data (arbitrary key-value pairs).
  • TLS certificates (used for HTTPS communication).
  • Docker registry credentials (for pulling private container images).

Can be consumed by pods through:

  • Environment variables
  • Volume mounts
  • Direct API calls from applications

Example: Creating a Secret

A Secret storing a database password:

apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  DB_PASSWORD: c2VjdXJlLXJvbmRvbS1wYXNzd29yZA==  # Base64-encoded value

To manually encode a password:

echo -n "secure-random-password" | base64

Once created (kubectl apply -f secret.yaml), this Secret can be used by pods.

Using a Secret in a Pod (Environment Variables)

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  containers:
  - name: my-app
    image: my-app-image
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: DB_PASSWORD

Using a Secret as a Volume

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  containers:
  - name: my-app
    image: my-app-image
    volumeMounts:
    - name: secret-volume
      mountPath: "/etc/secrets"
  volumes:
  - name: secret-volume
    secret:
      secretName: db-secret

The Secret will be accessible as a file at /etc/secrets/DB_PASSWORD.

Common Challenges

1. Base64 Encoding Is Not Encryption

  • Kubernetes stores Secrets Base64-encoded, but this does not provide encryption.
  • If etcd (the database storing Kubernetes data) is not encrypted, anyone with access can decode and read the Secrets.

2. Default Storage Is Insecure

  • By default, Secrets are stored unencrypted in etcd.
  • Kubernetes does not rotate or expire Secrets automatically.

3. Access Control Issues

  • By default, any pod in a namespace can access Secrets unless restricted.
  • Misconfigured RBAC rules can lead to unintended access to Secrets.

Best Practices

  • Enable Encryption at Rest – Configure Kubernetes to encrypt Secrets stored in etcd.
  • Use External Secret Management – Store Secrets in an external system like AWS Secrets Manager, HashiCorp Vault, or Google Secret Manager.
  • Restrict Access with RBAC – Ensure only necessary users and applications can access Secrets.
  • Use Ephemeral Secrets – Rotate and expire Secrets regularly instead of using long-lived credentials.
  • Avoid Mounting Secrets as Environment Variables – Environment variables are visible to processes and might be leaked in logs or debugging tools.
  • Use Immutable Secrets – Mark Secrets as immutable (kubectl annotate secret db-secret kubernetes.io/immutable=true) to prevent accidental changes.

Popular Tools for Managing Kubernetes Secrets

  • Sealed Secrets – Encrypts Secrets before storing them in Kubernetes.
  • External Secrets Operator – Syncs Kubernetes Secrets with cloud-based secret stores.
  • Vault by HashiCorp – A highly secure tool for managing secrets outside Kubernetes.
  • SOPS (Secrets OPerationS) – A tool for encrypting Kubernetes Secrets using GCP KMS, AWS KMS, or Azure Key Vault.

Further Reading