
August 19, 2026
10 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
Storing sensitive credentials as standard Kubernetes Secrets is a security liability because they are merely base64-encoded and stored unencrypted in etcd by default. Achieving Kubernetes Secrets Management Done Right requires integrating an external secret store, enabling encryption at rest on the API server, and enforcing strict role-based access controls to prevent credential leakage. This guide covers the exact architecture and configuration needed to secure production workloads in 2026, whether you are running on managed cloud infrastructure or self-hosted clusters.
For teams building scalable and efficient systems, treating secrets as immutable infrastructure artifacts rather than mutable configuration is the first step toward operational maturity. The native Kubernetes Secret resource was designed for convenience, not high-security compliance, which is why production environments must layer additional controls to meet audit and regulatory requirements.
Why Are Native Kubernetes Secrets Insufficient for Production?
The default Kubernetes Secret resource provides obfuscation, not security. When you run kubectl create secret generic db-pass --from-literal=password=mysecret, the value is base64-encoded and written directly to etcd. Anyone with read access to the etcd datastore, or any pod with permission to list secrets in that namespace, can retrieve the plaintext credential instantly. In my experience working on production Laravel applications deployed to Kubernetes, relying solely on native secrets creates three critical vulnerabilities that fail security audits immediately.
First, there is no built-in mechanism for automatic rotation. If a database password leaks, every deployment manifest, CI/CD variable, and local developer environment must be updated manually. Second, version control systems often accidentally capture these manifests during development, creating permanent credential exposure in git history. Third, audit logging for secret access is minimal in vanilla Kubernetes; you cannot easily determine who accessed a production database credential last Tuesday at 3 AM.
This is why Kubernetes Secrets Management Done Right always involves decoupling the secret lifecycle from the cluster lifecycle. The cluster should only ever hold short-lived, automatically synced references to authoritative secrets stored in a dedicated secrets manager. For teams evaluating current cybersecurity trends, this separation of concerns is now considered baseline hygiene, not advanced hardening.
How Do You Implement External Secrets Operator with Vault?
External Secrets Operator (ESO) has become the de facto standard for bridging Kubernetes and external secret stores in 2026. It runs as a controller inside your cluster, polls your external provider, and creates native Kubernetes Secrets that stay synchronized. This approach gives you the security of an external vault with the compatibility of native secret consumption in pods.
Install and Configure ESO with Helm
helm repo add external-secrets https://charts.external-secrets.io
helm repo update
helm install external-secrets \
external-secrets/external-secrets \
-n external-secrets \
--create-namespace \
--set installCRDs=true \
--set webhook.port=9443 After installation, configure a SecretStore resource that authenticates to HashiCorp Vault using Kubernetes service account tokens. This eliminates static credentials entirely:
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: vault-backend
spec:
provider:
vault:
server: "https://vault.internal:8200"
path: "secret/data"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "app-role"
serviceAccountRef:
name: "eso-vault-auth"
namespace: "external-secrets" Create ExternalSecret Resources for Application Credentials
Define an ExternalSecret that maps Vault paths to Kubernetes Secret keys. ESO handles synchronization, refresh intervals, and error handling automatically:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: laravel-db-credentials
namespace: production
spec:
refreshInterval: "1h"
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: laravel-db-secret
creationPolicy: Owner
data:
- secretKey: DB_PASSWORD
remoteRef:
key: secret/data/laravel/prod/db
property: password
- secretKey: DB_USERNAME
remoteRef:
key: secret/data/laravel/prod/db
property: username On a real client project running a legal-tech portal, we configured ESO to sync payment gateway credentials from Vault every 15 minutes. When the finance team rotated API keys in Vault, all running pods received updated credentials within the refresh window without redeployment. This eliminated the manual coordination that previously caused 30-minute maintenance windows for every credential rotation.
The key insight is that application code never knows it's consuming externally managed secrets. Your Laravel .env file still references DB_PASSWORD from the environment, and volume mounts work identically. ESO makes Kubernetes Secrets Management Done Right transparent to developers while enforcing security policy at the infrastructure level.
How Do You Enable Encryption at Rest for Kubernetes Secrets?
Even with External Secrets Operator, the synchronized Kubernetes Secrets exist in etcd. Without encryption at rest, a compromised etcd node exposes everything. Enabling EncryptionConfiguration is mandatory for any cluster handling PII, financial data, or regulated workloads. This is especially relevant when securing servers that handle Nepali legal or financial documents where data residency and protection requirements apply.
Generate Encryption Key and Configuration
head -c 32 /dev/urandom | base64
# Create encryption config on control plane
cat > /etc/kubernetes/encryption-config.yaml <<EOF
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: YOUR_BASE64_KEY_HERE
- identity: {}
EOF Configure API Server to Use Encryption
Edit the kube-apiserver manifest to mount and reference the encryption configuration:
# In /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
containers:
- command:
- kube-apiserver
- --encryption-provider-config=/etc/kubernetes/encryption-config.yaml
volumeMounts:
- name: encryption-config
mountPath: /etc/kubernetes/encryption-config.yaml
readOnly: true
volumes:
- name: encryption-config
hostPath:
path: /etc/kubernetes/encryption-config.yaml
type: File After the API server restarts, all new secrets are encrypted. Existing secrets remain unencrypted until rewritten. Force re-encryption across the cluster:
kubectl get secrets --all-namespaces -o json | \
kubectl replace -f - A common mistake is forgetting that the identity provider must appear after aescbc in the providers list. This ordering tells the API server to encrypt with AES-CBC but still allow reading unencrypted secrets during migration. Reversing the order breaks decryption. Always validate encryption status by reading a secret directly from etcd using etcdctl and confirming the value is ciphertext.
| Encryption Provider | Performance Impact | Key Rotation Support | Recommended Use Case |
|---|---|---|---|
| aescbc | Moderate (~5% overhead) | Manual rotation required | Self-managed clusters, broad compatibility |
| aesgcm | Low (~2% overhead) | Manual rotation required | High-throughput API servers |
| KMS v2 (AWS/GCP/Azure) | Network latency dependent | Automatic via cloud KMS | Managed Kubernetes, compliance workloads |
| identity | None | N/A | Development only, never production |
What RBAC Policies Restrict Secret Access Effectively?
Encryption protects data at rest, but RBAC prevents unauthorized access through the API. Most clusters grant far more secret access than necessary. Implementing least-privilege RBAC is where Kubernetes Secrets Management Done Right moves from theoretical to operational reality.
Audit Current Secret Permissions
Before tightening policies, understand current access patterns:
# Find all roles granting secret access
kubectl get clusterroles,roles --all-namespaces -o json | \
jq '.items[] | select(.rules[]?.resources[]? == "secrets") |
{name: .metadata.name, namespace: .metadata.namespace, verbs: .rules[].verbs}'
# Check who can list secrets cluster-wide
kubectl auth can-i --list --as=system:serviceaccount:default:my-app | grep secrets Create Namespace-Scoped Secret Roles
Never grant cluster-wide secret access. Create specific roles per application:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: laravel-secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["laravel-db-secret", "laravel-cache-secret"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: laravel-pod-secret-access
namespace: production
subjects:
- kind: ServiceAccount
name: laravel-app
namespace: production
roleRef:
kind: Role
name: laravel-secret-reader
apiGroup: rbac.authorization.k8s.io Note the resourceNames field. This restricts access to specific secrets only. Without it, the service account can read every secret in the namespace, defeating the purpose of isolation. On a multi-tenant legal platform I worked on, we enforced this pattern strictly: each microservice could only access its own credentials, and shared secrets were explicitly named and audited quarterly.
Block Secret Listing Entirely
Most applications need to get specific secrets but never need to list them. Listing exposes secret names and metadata even if values aren't returned. Remove list and watch verbs from all application-facing roles unless absolutely required. Audit logs should flag any service account attempting to list secrets as a potential compromise indicator.
How Do You Rotate Secrets Without Downtime?
Secret rotation is where most implementations fail operationally. Applications cache credentials in memory, connection pools hold stale passwords, and rolling restarts cause brief authentication failures. Getting rotation right requires coordinating the secret store, ESO sync interval, and application behavior.
- Update the source secret in Vault/Cloud provider first. Never edit the Kubernetes Secret directly; ESO will overwrite it on next sync.
- Wait for ESO refresh interval to elapse or trigger immediate sync:
kubectl annotate externalsecret laravel-db-credentials force-sync=$(date +%s) --overwrite - Verify the Kubernetes Secret updated:
kubectl get secret laravel-db-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 -d - Gracefully restart affected pods to pick up new credentials:
kubectl rollout restart deployment/laravel-app -n production - Monitor application logs for authentication errors during the transition window.
For databases supporting multiple simultaneous passwords, configure Vault to maintain both old and new credentials during a grace period. This eliminates the race condition between secret update and pod restart. Applications like Laravel with persistent database connections benefit from connection pool recycling configurations that detect credential changes without full process restart.
In practice, teams using DevOps automation should script this entire rotation workflow. Manual rotation inevitably leads to skipped steps, forgotten pods, and 3 AM incident calls. Automate the verification step especially: if the new credential doesn't authenticate successfully in a test query, halt the rotation and alert before proceeding.
Kubernetes Secrets Management Done Right Requires Layered Defense
Implementing Kubernetes Secrets Management Done Right is not a single tool installation but a layered security posture combining external secret stores, encryption at rest, granular RBAC, and automated rotation workflows. Start with External Secrets Operator connected to your existing vault infrastructure, enable API server encryption immediately, and audit RBAC permissions quarterly. These three actions eliminate the majority of secret-related vulnerabilities seen in production clusters today.
If your team needs help designing or auditing a secrets management architecture that meets compliance requirements without slowing development velocity, reach out to discuss your specific infrastructure. Secure secret handling is foundational to trustworthy systems, and getting it right early prevents costly remediation later.

