Kubernetes Secrets Management: 12 Mistakes That Expose Your Cluster (and How to Fix Them)

Learn the 12 most critical Kubernetes secrets management mistakes that expose production clusters to attacks, and follow concrete fixes with RBAC, encryption, and External Secrets Operator examples.

Kubernetes Secrets Management: 12 Mistakes That Expose Your Cluster (and How to Fix Them)

Kubernetes secrets are not actually secret. By default, they are stored as base64-encoded plain text in etcd, accessible to anyone with API server access, visible in pod specs, and often committed to Git repositories by accident. For a platform built to manage containerized workloads at scale, this is a surprising gap — and it is one of the most common attack vectors in Kubernetes environments today.

In this guide, we cover twelve specific Kubernetes secrets management mistakes that teams make in production, and the exact fixes that close each gap. If you are running workloads on Kubernetes and storing any sensitive data — API keys, database passwords, TLS certificates, or cloud credentials — these practices apply to your cluster right now.

Why Kubernetes Secrets Management Matters More Than Ever

Kubernetes has become the default orchestration platform for containerized applications, with over 5 million clusters running globally according to recent CNCF surveys. Every one of these clusters uses secrets of some kind. Yet the default Kubernetes secrets implementation leaves most of the security work to the cluster operator.

High-profile breaches in the last two years consistently traced back to exposed Kubernetes secrets: a cloud provider credential stored in a ConfigMap, a database password committed to a public Helm chart, a service account token with cluster-admin privileges leaked through a pod's environment variables. In every case, the technology was not the problem; the secrets management practice was.

Because of the shared nature of Kubernetes clusters, a single exposed secret can compromise every workload on that cluster. If an attacker gains access to a secret with cross-namespace permissions, they can pivot from a low-priority application to a production database within minutes. Treating secrets as first-class security objects, not as afterthoughts in a YAML file, is the single highest-leverage security investment you can make in your Kubernetes environment.

Kubernetes secrets management workflow: Create, Encrypt, Access Control, Inject, Rotate

Mistake 1: Treating Base64 as Encryption

The most dangerous misconception in Kubernetes secrets management is assuming that base64 encoding is encryption. It is not. Base64 is encoding, trivially reversible by anyone with access to the encoded string. Runningecho 'cGFzc3dvcmQ=' | base64 -d takes less than a second.

The fix:Enable encryption at rest for etcd. This is the single most impactful change you can make.

# Create an encryption configuration file
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources: [secrets]
    providers:
      - aesgcm:
          keys:
            - name: key1
              secret: $(openssl rand -base64 32)
      - identity: {}

Pass this configuration to the API server using the--encryption-provider-config flag. Once enabled, all secrets are encrypted at rest in etcd using AES-GCM or AES-CBC. Without this, anyone with direct etcd access — including backup administrators — can read every secret in your cluster.

Kubernetes has supported encryption at rest since v1.7, yet a surprising number of production clusters still run without it. Check yours today withkubectl get --raw /api/v1/namespaces/kube-system/configmaps/encryption-config.

Mistake 2: Not Restricting Access to Secrets via RBAC

By default, any authenticated user or service account can list and read secrets in namespaces they have access to. This means a compromised CI/CD runner, a misconfigured monitoring agent, or even a developer's local kubeconfig can expose every secret in a namespace.

The fix:Apply least-privilege RBAC for secrets access explicitly.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: namespace: production
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata: namespace: production
  name: app-secret-reader
subjects:
- kind: ServiceAccount
  name: my-app
roleRef:
  kind: Role
  name: secret-reader

Never grantlist or watch permissions on secrets unless a specific use case requires it. The difference between get and list is significant: list returns all secrets in a namespace, while get requires the caller to know the exact secret name. Restrict create, update, and delete permissions to cluster administrators only.

Kubernetes RBAC access control diagram showing different permission levels for admin, developer, CI/CD, and service accounts

Mistake 3: Storing Secrets in Environment Variables Without Encryption

Passing secrets to pods via environment variables is convenient, but it leaks secrets into the pod spec, which is visible to anyone withkubectl describe pod access, in audit logs, and often in monitoring dashboards.

The fix:Mount secrets as volumes instead of environment variables where possible, and always use encryption at rest.

apiVersion: v1
kind: Pod
metadata: name: secure-app
spec:
  containers:
  - name: app
    image: myapp:latest
    volumeMounts:
    - name: db-credentials
      mountPath: /etc/credentials
      readOnly: true
  volumes:
  - name: db-credentials
    secret:
      secretName: db-secret

When you mount secrets as volumes, the data is available only inside the running container and is not exposed through the Kubernetes API after the pod is created. Combined with read-only filesystems and non-root containers, this significantly limits the blast radius of a compromised pod.

Mistake 4: Committing Secrets to Git Repositories

Committing Kubernetes secret manifests to version control is one of the most widespread security anti-patterns. Once a secret is in Git, it is there forever, even if you delete it in a later commit. Services like GitHub's secret scanning can detect some exposures, but the damage is often already done.

The fix:Use a GitOps workflow with sealed secrets or an external secrets operator.

# Create a SealedSecret
kubeseal --format yaml < secret.yaml > sealed-secret.yaml

# Commit and deploy the SealedSecret
git add sealed-secret.yaml
git commit -m "Add production database secrets"
git push

SealedSecrets are encrypted by a controller in your cluster and can be safely committed to public or private repositories. Only the cluster running the Sealed Secrets controller can decrypt them.

Secure GitOps workflow: encrypted SealedSecrets flowing from Git repository to Kubernetes cluster

For more advanced use cases, theExternal Secrets Operatorintegrates with cloud secret managers like AWS Secrets Manager, GCP Secret Manager, and HashiCorp Vault.

Mistake 5: Hardcoding Service Account Tokens in Pod Specs

Kubernetes automatically mounts a service account token into every pod. By default, this token is bound to the pod's service account and mounts at/var/run/secrets/kubernetes.io/serviceaccount/token. Attackers who compromise a pod can exfiltrate this token and use it to make API calls with the service account's permissions.

The fix:Disable automatic token mounting and use projected volumes with time-bound tokens.

apiVersion: v1
kind: Pod
metadata: name: secure-pod
spec:
  automountServiceAccountToken: false
  containers:
  - name: app
    image: myapp:latest

If your application needs to make API calls, mount a projected volume with a time-bound, audience-restricted token:

projected:
  sources:
  - serviceAccountToken:
      path: token
      expirationSeconds: 3600
      audience: kubernetes

This approach ensures that tokens are short-lived and scoped to specific audiences, drastically reducing the window of exposure if a token is compromised.

Mistake 6: Storing Secrets in ConfigMaps

ConfigMaps are not designed for sensitive data. They are stored in plain text in etcd, visible through the Kubernetes API, and often logged. Despite this, teams sometimes store credentials in ConfigMaps because they treat all configuration data the same way.

The fix:Always usekind: Secret for sensitive data, never ConfigMap. Enable encryption at rest for secrets. If you need to manage large volumes of secrets, use an external secrets manager with the External Secrets Operator or a dedicated secrets store CSI driver.

Mistake 7: Using Namespace-Wide Service Accounts with ClusterRole Bindings

A service account bound to a ClusterRole with broad permissions can access secrets across all namespaces. If a pod using this service account is compromised, the attacker has immediate access to every namespace's secrets.

The fix:Use namespace-scoped service accounts with specific Roles. Audit all ClusterRoleBindings regularly and remove any that grant unnecessary cross-namespace access to secrets.

kubectl get clusterrolebindings -o wide | grep -i secret
kubectl describe clusterrolebinding 

Know exactly which service accounts have cross-namespace secret access and why.

Mistake 8: Not Rotating Secrets Regularly

Secrets that never rotate become more valuable over time. A credential that was valid when the application was deployed may still be valid years later, long after the original key should have been retired. Kubernetes Secrets do not automatically rotate, so this is entirely on the operator.

The fix:Implement automated secret rotation using the External Secrets Operator or a reconciliation loop.

apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata: name: aws-secrets-manager
spec:
  provider:
    aws:
      service: SecretsManager
      region: us-east-1
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata: name: db-credentials
spec:
  refreshInterval: 24h
  secretStoreRef:
    name: aws-secrets-manager
  target:
    name: db-secret
  data:
  - secretKey: password
    remoteRef:
      key: production/db/password

SetrefreshInterval to match your security policy for secret rotation. When the value changes in the external manager, the External Secret is updated automatically, and you can trigger pod reloads using tools like Reloader or Stakater.

Mistake 9: Logging Secrets in Application Logs

Applications often log environment variables or configuration data during startup, which frequently includes secrets. These logs end up in centralized logging systems, SIEM tools, and sometimes public log aggregation services.

The fix:Implement secret scrubbing in your logging pipeline. Use structured logging and explicitly exclude sensitive fields. For Kubernetes audit logs, ensure that theaudit-log-maxbackup and audit-log-maxage flags are configured to limit exposure. For Falcoruntime security rules, add alerts for processes that read secret files and write to stdout.

Mistake 10: Relying on Default Kubernetes Secrets Without External Integration

The built-in Kubernetes Secret resource is functional but limited. It lacks automatic rotation, audit trails for secret access, integration with cloud secret stores, and fine-grained access policies beyond RBAC. For production environments, relying solely on native Secrets is a significant gap.

The fix:Integrate Kubernetes Secrets with an enterprise secret management platform. TheExternal Secrets Operatorbridges Kubernetes Secrets with AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, and HashiCorp Vault. For Vault specifically, the Vault Agent Injector can inject secrets directly into pods without them ever being stored in Kubernetes Secrets at all.

Mistake 11: Exposing Secrets Through Third-Party Helm Charts

Public Helm charts for popular tools often include default values with placeholder secrets or, worse, documented examples showing how to pass sensitive data directly in values files that get committed to Git.

The fix:Audit all Helm charts for secret handling before deploying. Override default values with your secrets management approach. Use a GitOps tool like ArgoCD or Flux that integrates with SealedSecrets or External Secrets to avoid plain-text secrets in your Git repository.

Mistake 12: Not Having an Incident Response Plan for Secret Exposure

When a secret is compromised — and it will happen — teams without a plan waste critical hours deciding what to do. The longer a compromised secret remains valid, the more damage an attacker can do.

The fix:Create a documented incident response plan for secret exposure that includes:

  • Immediate revocation of the exposed secret
  • Rotation of all secrets that share the same access scope
  • Audit log review to determine the blast radius
  • Notification to affected teams and stakeholders
  • Post-mortem to identify the root cause and prevent recurrence

Automated tools can help: configure the External Secrets Operator to rotate secrets on-demand, useKubernetes Pod Security Standardsto prevent privileged containers that could exfiltrate secrets, and run regular penetration tests that include secret extraction scenarios.

Kubernetes Secrets Management Checklist

Use this checklist to audit your current secrets management posture:

  • ⬜ Encryption at rest is enabled for etcd secrets
  • ⬜ RBAC restricts secret access to only what each workload needs
  • ⬜ Secrets are mounted as volumes, not environment variables
  • ⬜ No secrets are committed to Git repositories
  • ⬜ Automatic service account token mounting is disabled where not needed
  • ⬜ Service account tokens use projected volumes with short expiration
  • ⬜ ConfigMaps do not contain sensitive data
  • ⬜ Secrets are rotated at regular intervals
  • ⬜ External Secrets Operator or equivalent is integrated for production
  • ⬜ Application logs are scrubbed of sensitive data
  • ⬜ Helm charts are audited for secret handling before deployment
  • ⬜ Incident response plan for secret exposure exists and is tested

Frequently Asked Questions

Are Kubernetes Secrets secure by default?

No. By default, Kubernetes Secrets are stored as base64-encoded plain text in etcd. They are not encrypted at rest, and access control depends entirely on RBAC configuration, which is often misconfigured.

What is the difference between a Secret and a ConfigMap?

Both store key-value pairs, but Secrets are intended for sensitive data. The key differences are: Secrets support encryption at rest, have different RBAC verbs, and use base64 encoding (not plain text) in manifests. However, Secrets are not more secure than ConfigMaps unless you enable encryption at rest and proper RBAC.

Should I use HashiCorp Vault or cloud-native secret managers with Kubernetes?

Both approaches work well. HashiCorp Vault offers rich policy and audit capabilities. Cloud-native options like AWS Secrets Manager, GCP Secret Manager, and Azure Key Vault integrate tightly with their respective ecosystems. The External Secrets Operator supports all of them and provides a consistent Kubernetes-native API.

How often should Kubernetes secrets be rotated?

Industry best practice recommends every 90 days for static credentials and immediately upon any suspected compromise. For service account tokens, use short-lived tokens with expiration measured in hours, not days.

Can SealedSecrets replace a dedicated secret management platform?

SealedSecrets are excellent for GitOps workflows because they allow secrets to be committed to Git safely. However, they do not provide automatic rotation, audit logging, or integration with external secret stores. They are a strong layer in your strategy, but not a complete replacement for a dedicated secret management platform.

Conclusion

Kubernetes secrets management is not a single tool or configuration. It is a practice that spans encryption, access control, rotation, auditing, and incident response. The twelve mistakes in this guide are common because the defaults are permissive and the configuration surface is large, but each one has a straightforward fix.

Start with the highest-impact changes: enable encryption at rest for etcd, audit your RBAC for secrets access, and stop mounting secrets as environment variables. Then add SealedSecrets or External Secrets Operator to your GitOps pipeline. Finally, automate rotation and build an incident response plan for the inevitable exposure event.

If you are unsure where your current Kubernetes secrets management stands, start with an audit of who can access which secrets in your cluster today. That single exercise will tell you exactly which of these twelve mistakes exist in your environment, and those are the ones to fix first.

Ready to apply these concepts?

Scan your Kubernetes manifests for RBAC gaps, policy issues, and misconfigurations.

Scan Your Kubernetes Cluster

Your take

Rate this article or leave a comment

Have more questions? Check our

FAQ
🤖