Kubernetes Secrets Management
Introduction
When deploying applications in Kubernetes, you'll often need to use sensitive information such as passwords, API keys, and tokens. Storing this information directly in your configuration files or container images creates security vulnerabilities. Kubernetes Secrets provide a solution to this problem by offering a secure way to store and manage sensitive information.
In this guide, we'll explore how Kubernetes Secrets work, how to create and use them, and best practices for managing sensitive information in your Kubernetes clusters.
What are Kubernetes Secrets?
Kubernetes Secrets are objects that store sensitive data such as passwords, OAuth tokens, and SSH keys. By using Secrets, you can separate your sensitive information from your application code and configuration, reducing the risk of accidental exposure.
Secrets are similar to ConfigMaps but are specifically intended for confidential data. Kubernetes provides additional safeguards for Secret objects:
- Secrets are stored in a temporary file-system (tmpfs) rather than on disk
- Secrets are only distributed to nodes that run pods requiring them
- Secrets are encoded in base64 by default (though this is not encryption)
Let's visualize how Secrets fit into the Kubernetes ecosystem:
Creating Secrets
There are several ways to create Secrets in Kubernetes:
1. Creating from literal values
You can create a Secret directly from the command line:
kubectl create secret generic db-credentials \
--from-literal=username=admin \
--from-literal=password=mysecretpassword
2. Creating from files
If you have sensitive data stored in files, you can create a Secret from them:
# First, create files containing your secret data
echo -n 'admin' > ./username.txt
echo -n 'mysecretpassword' > ./password.txt
# Then, create a secret from these files
kubectl create secret generic db-credentials \
--from-file=username=./username.txt \
--from-file=password=./password.txt
3. Creating from YAML
You can also define a Secret in a YAML file. However, you'll need to encode your sensitive data in base64 first:
echo -n 'admin' | base64
# Output: YWRtaW4=
echo -n 'mysecretpassword' | base64
# Output: bXlzZWNyZXRwYXNzd29yZA==
Then create a YAML file:
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
username: YWRtaW4=
password: bXlzZWNyZXRwYXNzd29yZA==
Apply the YAML file:
kubectl apply -f secret.yaml
Using Secrets in Pods
There are two main ways to use Secrets in your pods:
1. As environment variables
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-app-container
image: my-app:1.0
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
2. As mounted volumes
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: my-app-container
image: my-app:1.0
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: db-credentials
When using volume mounts, each key in the Secret becomes a file in the mounted directory. For example, with the above configuration:
/etc/secrets/username
will containadmin
/etc/secrets/password
will containmysecretpassword
Real-world Example: Deploying a Database with Secrets
Let's walk through a complete example of deploying a PostgreSQL database that uses Secrets for authentication:
Step 1: Create a Secret for database credentials
kubectl create secret generic postgres-credentials \
--from-literal=POSTGRES_USER=myuser \
--from-literal=POSTGRES_PASSWORD=mysecretpassword \
--from-literal=POSTGRES_DB=mydb
Step 2: Deploy PostgreSQL using the Secret
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:13
ports:
- containerPort: 5432
envFrom:
- secretRef:
name: postgres-credentials
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-storage
emptyDir: {}
Step 3: Deploy an application that connects to the database
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-app:1.0
env:
- name: DB_HOST
value: "postgres"
- name: DB_PORT
value: "5432"
- name: DB_USER
valueFrom:
secretKeyRef:
name: postgres-credentials
key: POSTGRES_USER
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-credentials
key: POSTGRES_PASSWORD
- name: DB_NAME
valueFrom:
secretKeyRef:
name: postgres-credentials
key: POSTGRES_DB
Best Practices for Kubernetes Secrets
While Secrets provide a way to manage sensitive information, they're not completely secure by default. Here are some best practices:
1. Enable Encryption at Rest
By default, Secrets are stored unencrypted in etcd. Enable encryption at rest to add an extra layer of security:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-key>
- identity: {}
2. Use RBAC to control access to Secrets
Limit who can read or modify Secrets using Role-Based Access Control:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"]
3. Implement Pod Security Policies
Restrict which pods can mount specific Secrets:
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restrict-secrets
spec:
volumes:
- 'secret'
# Other settings...
4. Consider external Secret management solutions
For production environments, consider using external secrets management tools like:
- HashiCorp Vault
- AWS Secrets Manager
- Azure Key Vault
- Google Secret Manager
These solutions offer additional features like automatic rotation, versioning, and audit trails.
External Secrets Management Integration
Let's look at a brief example of integrating with HashiCorp Vault using the Vault Agent Injector:
- Install the Vault Helm chart:
helm repo add hashicorp https://helm.releases.hashicorp.com
helm install vault hashicorp/vault
- Annotate your pods to use Vault secrets:
apiVersion: apps/v1
kind: Deployment
metadata:
name: vault-example
spec:
replicas: 1
selector:
matchLabels:
app: vault-example
template:
metadata:
labels:
app: vault-example
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-inject-secret-database-config.txt: "database/creds/db-role"
vault.hashicorp.com/role: "db-app"
spec:
containers:
- name: app
image: app:1.0
This will inject a file at /vault/secrets/database-config.txt
with credentials from Vault.
Common Pitfalls and Troubleshooting
Base64 is not encryption
Remember that base64 encoding is not encryption—it's just an encoding format:
# You can easily decode base64
echo "bXlzZWNyZXRwYXNzd29yZA==" | base64 --decode
# Output: mysecretpassword
Secret size limitations
Secrets are limited to 1MB in size. For larger files, consider using encrypted volumes instead.
Secret immutability
Secrets are immutable—you can't update them directly. Instead, you need to:
- Create a new Secret
- Update your deployments to use the new Secret
- Delete the old Secret (once nothing references it)
Summary
Kubernetes Secrets provide a way to store and manage sensitive information separately from your application code. They can be consumed as environment variables or mounted as volumes, giving flexibility in how your applications access confidential data.
Remember these key points:
- Secrets are not encrypted by default—implement encryption at rest
- Base64 encoding is not a security measure
- Use RBAC to control access to Secrets
- Consider external solutions for additional security features
By following best practices for Secrets management, you can significantly improve the security posture of your Kubernetes applications.
Further Resources
- Kubernetes Documentation on Secrets
- HashiCorp Vault Kubernetes Integration
- Sealed Secrets for Kubernetes
Exercises
-
Create a Secret with multiple key-value pairs and consume it in a Pod both as environment variables and as mounted files.
-
Set up encryption at rest for Secrets in a test cluster.
-
Create a role and role binding that allows a service account to read only specific Secrets.
-
Install and configure an external secrets manager (like HashiCorp Vault) and integrate it with your Kubernetes cluster.
-
Create a deployment that uses Secrets for database credentials, then update the Secret with new credentials, and finally update the deployment to use the new Secret.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)