Kubernetes Configuration & Security
category: DevOps
tags: kubernetes, k8s, configuration, configmap, secret, serviceaccount, rbac
ConfigMap
What it is: A Kubernetes object that stores non-confidential configuration data in key-value pairs, allowing you to decouple configuration from application code.
Why it matters: ConfigMaps enable configuration portability across environments, make applications more flexible, and allow configuration changes without rebuilding container images. They're essential for managing environment-specific settings.
ConfigMap use cases:
- Application configuration - Database URLs, API endpoints, feature flags
- Configuration files - nginx.conf, application.properties, config.yaml
- Environment variables - Runtime settings for applications
- Command-line arguments - Parameters for container commands
Ways to consume ConfigMaps:
- Environment variables - Inject config as env vars
- Volume mounts - Mount config as files in containers
- Command arguments - Use config values in container commands
Common commands:
# ConfigMap creation
kubectl create configmap app-config --from-literal=database_url=postgres://localhost:5432/mydb
kubectl create configmap app-config --from-file=config.properties
kubectl create configmap app-config --from-file=config-dir/
kubectl create configmap app-config --from-env-file=.env
# ConfigMap operations
kubectl get configmaps # List all ConfigMaps
kubectl get cm # Short form
kubectl describe configmap <cm-name> # Detailed ConfigMap info
kubectl delete configmap <cm-name> # Delete ConfigMap
# View ConfigMap data
kubectl get configmap <cm-name> -o yaml # YAML output
kubectl get configmap <cm-name> -o json # JSON output
Example ConfigMap YAML:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
data:
# Key-value pairs
database_host: "postgres-service"
database_port: "5432"
log_level: "INFO"
enable_debug: "false"
# File-like keys
application.properties: |
server.port=8080
spring.datasource.url=jdbc:postgresql://postgres-service:5432/mydb
spring.datasource.username=appuser
logging.level.com.mycompany=INFO
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://backend-service:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Using ConfigMap as environment variables:
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app-container
image: myapp:v1.0
env:
# Single environment variable from ConfigMap
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: database_host
# All keys from ConfigMap as environment variables
envFrom:
- configMapRef:
name: app-config
Using ConfigMap as volume mount:
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:1.21
volumeMounts:
- name: config-volume
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
- name: app-config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
items:
- key: nginx.conf
path: nginx.conf
- name: app-config-volume
configMap:
name: app-config
ConfigMap from files example:
# Create config files
echo "database_url=postgres://localhost:5432/mydb" > database.conf
echo "redis_url=redis://localhost:6379" > cache.conf
# Create ConfigMap from files
kubectl create configmap file-config \
--from-file=database.conf \
--from-file=cache.conf
# Create ConfigMap from directory
kubectl create configmap dir-config --from-file=config-dir/
ConfigMap best practices:
- Separate by environment - Different ConfigMaps for dev/staging/prod
- Version your configs - Use labels or annotations for versioning
- Limit size - ConfigMaps have 1MB size limit
- Use meaningful names - Clear naming for keys and ConfigMaps
- Don't store secrets - Use Secrets for sensitive data
Secret
What it is: A Kubernetes object that stores sensitive information such as passwords, OAuth tokens, SSH keys, and TLS certificates in base64 encoded format.
Why it matters: Secrets provide secure storage and distribution of sensitive data, keeping credentials out of container images and pod specifications. They're essential for security best practices in Kubernetes.
Secret types:
- Opaque - Arbitrary user-defined data (default)
- kubernetes.io/service-account-token - Service account tokens
- kubernetes.io/dockercfg - Docker registry authentication
- kubernetes.io/dockerconfigjson - Docker registry authentication (new format)
- kubernetes.io/basic-auth - Basic authentication credentials
- kubernetes.io/ssh-auth - SSH authentication credentials
- kubernetes.io/tls - TLS certificates and keys
Security features:
- Base64 encoding - Not encryption, just encoding
- etcd encryption - Can be encrypted at rest in etcd
- In-memory storage - Secrets mounted as tmpfs in containers
- Access control - RBAC controls who can access secrets
Common commands:
# Secret creation
kubectl create secret generic db-secret --from-literal=username=admin --from-literal=password=secretpassword
kubectl create secret generic db-secret --from-file=username.txt --from-file=password.txt
kubectl create secret tls tls-secret --cert=tls.crt --key=tls.key
kubectl create secret docker-registry regcred --docker-server=myregistry.com --docker-username=user --docker-password=pass
# Secret operations
kubectl get secrets # List all secrets
kubectl describe secret <secret-name> # Detailed secret info (values hidden)
kubectl delete secret <secret-name> # Delete secret
# View secret data (base64 decoded)
kubectl get secret <secret-name> -o jsonpath='{.data.username}' | base64 -d
kubectl get secret <secret-name> -o yaml # YAML output (base64 encoded)
Example Secret YAML:
apiVersion: v1
kind: Secret
metadata:
name: database-secret
namespace: production
type: Opaque
data:
username: YWRtaW4= # admin (base64 encoded)
password: cGFzc3dvcmQxMjM= # password123 (base64 encoded)
database-url: cG9zdGdyZXM6Ly9hZG1pbjpwYXNzd29yZDEyM0BkYi5leGFtcGxlLmNvbTo1NDMyL215ZGI=
Using Secrets as environment variables:
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app-container
image: myapp:v1.0
env:
# Single environment variable from Secret
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: database-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: database-secret
key: password
# All keys from Secret as environment variables
envFrom:
- secretRef:
name: database-secret
Using Secrets as volume mounts:
apiVersion: v1
kind: Pod
metadata:
name: app-with-secrets
spec:
containers:
- name: app
image: myapp:v1.0
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: database-secret
defaultMode: 0400 # Read-only for owner only
items:
- key: username
path: db-username
- key: password
path: db-password
TLS Secret example:
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
type: kubernetes.io/tls
data:
tls.crt: LS0tLS1CRUdJTi... # base64 encoded certificate
tls.key: LS0tLS1CRUdJTi... # base64 encoded private key
Docker registry Secret:
apiVersion: v1
kind: Secret
metadata:
name: regcred
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: eyJhdXRocyI6eyJteS1yZWdpc3RyeS5jb20iOnsidXNlcm5hbWUiOiJ1c2VyIiwicGFzc3dvcmQiOiJwYXNzIiwiYXV0aCI6ImRYTmxjam
Using registry Secret in Pod:
apiVersion: v1
kind: Pod
metadata:
name: private-reg-pod
spec:
containers:
- name: app
image: my-private-registry.com/myapp:v1.0
imagePullSecrets:
- name: regcred
Secret best practices:
- Principle of least privilege - Only give access to secrets that are needed
- Use RBAC - Control who can read/write secrets
- Enable encryption at rest - Encrypt etcd data
- Rotate secrets regularly - Update passwords and certificates
- Avoid logging secrets - Don't log secret values in applications
- Use external secret management - Consider tools like Vault, AWS Secrets Manager
ServiceAccount
What it is: A Kubernetes resource that provides an identity for processes running in pods, enabling authentication and authorization for API access.
Why it matters: ServiceAccounts enable secure pod-to-API communication, implement least privilege access, and provide audit trails for API operations. They're essential for pods that need to interact with the Kubernetes API.
ServiceAccount components:
- Identity - Unique identity for pods
- Token - JWT token for API authentication
- Secrets - Automatically created secret with token
- RBAC bindings - Permissions granted through roles
Default behavior:
- Default ServiceAccount - Every namespace has a default ServiceAccount
- Automatic mounting - Tokens automatically mounted in pods at /var/run/secrets/kubernetes.io/serviceaccount/
- Limited permissions - Default ServiceAccount has minimal permissions
Common commands:
# ServiceAccount operations
kubectl get serviceaccounts # List all service accounts
kubectl get sa # Short form
kubectl describe serviceaccount <sa-name> # Detailed SA info
kubectl delete serviceaccount <sa-name> # Delete service account
# ServiceAccount tokens
kubectl get secret # List secrets (includes SA tokens)
kubectl describe secret <sa-token-secret> # View token details
Example ServiceAccount:
apiVersion: v1
kind: ServiceAccount
metadata:
name: pod-reader
namespace: production
automountServiceAccountToken: true
imagePullSecrets:
- name: private-registry-secret
secrets:
- name: pod-reader-token
Using ServiceAccount in Pod:
apiVersion: v1
kind: Pod
metadata:
name: api-client-pod
spec:
serviceAccountName: pod-reader
containers:
- name: api-client
image: kubectl:latest
command: ['sh', '-c']
args:
- |
# Token is automatically mounted
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
# Use token to authenticate API calls
curl -H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
https://kubernetes.default.svc/api/v1/namespaces/$NAMESPACE/pods
Disable automatic token mounting:
apiVersion: v1
kind: Pod
metadata:
name: no-token-pod
spec:
serviceAccountName: pod-reader
automountServiceAccountToken: false # Disable token mounting
containers:
- name: app
image: myapp:v1.0
ServiceAccount with ImagePullSecrets:
apiVersion: v1
kind: ServiceAccount
metadata:
name: builder-sa
imagePullSecrets:
- name: docker-hub-secret
- name: private-registry-secret
RBAC (Role-Based Access Control)
What it is: Kubernetes authorization mechanism that regulates access to resources based on the roles assigned to users, groups, or service accounts.
Why it matters: RBAC implements security principle of least privilege, provides fine-grained access control, enables compliance with security policies, and allows secure multi-tenancy in Kubernetes clusters.
RBAC components:
- Role/ClusterRole - Defines permissions (what can be done)
- RoleBinding/ClusterRoleBinding - Grants permissions to subjects (who can do it)
- Subjects - Users, groups, or service accounts that receive permissions
Scope differences:
- Role/RoleBinding - Namespace-scoped permissions
- ClusterRole/ClusterRoleBinding - Cluster-wide permissions
Common commands:
# Role operations
kubectl get roles # List roles in current namespace
kubectl get roles --all-namespaces # List roles in all namespaces
kubectl describe role <role-name> # Detailed role info
kubectl delete role <role-name> # Delete role
# ClusterRole operations
kubectl get clusterroles # List all cluster roles
kubectl describe clusterrole <clusterrole-name> # Detailed cluster role info
# RoleBinding operations
kubectl get rolebindings # List role bindings
kubectl describe rolebinding <binding-name> # Detailed binding info
# ClusterRoleBinding operations
kubectl get clusterrolebindings # List cluster role bindings
kubectl describe clusterrolebinding <binding-name> # Detailed cluster binding info
# Check permissions
kubectl auth can-i get pods # Check if you can get pods
kubectl auth can-i get pods --as=system:serviceaccount:default:pod-reader # Check as specific SA
kubectl auth can-i '*' '*' # Check if you have all permissions
Example Role (namespace-scoped):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""] # Core API group
resources: ["pods"]
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
- apiGroups: ["apps"] # Apps API group
resources: ["deployments"]
verbs: ["get", "list"]
Example ClusterRole (cluster-wide):
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "watch", "list"]
- apiGroups: ["metrics.k8s.io"]
resources: ["nodes", "pods"]
verbs: ["get", "list"]
Example RoleBinding:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: production
subjects:
- kind: User
name: jane.doe
apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount
name: pod-reader
namespace: production
- kind: Group
name: developers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Example ClusterRoleBinding:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-admin-binding
subjects:
- kind: User
name: admin@company.com
apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount
name: cluster-admin-sa
namespace: kube-system
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
Common RBAC patterns:
Read-only access to specific resources:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: viewer
rules:
- apiGroups: ["", "apps", "extensions"]
resources: ["*"]
verbs: ["get", "list", "watch"]
Developer access (no secrets):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
rules:
- apiGroups: ["", "apps", "extensions"]
resources: ["*"]
verbs: ["*"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"] # Read-only access to secrets
CI/CD ServiceAccount:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: ci-cd-role
rules:
- apiGroups: ["", "apps", "extensions"]
resources: ["deployments", "services", "configmaps"]
verbs: ["get", "list", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "create", "update"]
RBAC best practices:
- Principle of least privilege - Grant minimum necessary permissions
- Use Groups - Assign roles to groups rather than individual users
- Regular audits - Review and clean up unused permissions
- Separate environments - Different RBAC rules for dev/staging/prod
- Document permissions - Clear documentation of who has what access
- Monitor access - Use audit logs to track API access
Built-in ClusterRoles:
- cluster-admin - Full access to everything
- admin - Full access within namespace
- edit - Read/write access within namespace
- view - Read-only access within namespace
- system:node - Access for kubelets
- system:discovery - Access for discovery information
When you'll use them: ConfigMaps and Secrets are used in almost every Kubernetes application for configuration management. ServiceAccounts and RBAC are essential for any production environment requiring proper security and access control.