Amazon EKS — ConfigMaps and Secrets
Application configuration on EKS involves Kubernetes-native ConfigMaps and Secrets, plus AWS-specific integrations like AWS Secrets Manager and Parameter Store.
ConfigMaps
ConfigMaps store non-sensitive configuration data:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: production
data:
APP_ENV: "production"
LOG_LEVEL: "info"
MAX_CONNECTIONS: "100"
config.json: |
{
"feature_flags": {
"new_ui": true,
"dark_mode": false
}
}
Consume as Environment Variables
spec:
containers:
- name: app
envFrom:
- configMapRef:
name: app-config
Consume as Volume Mount
spec:
containers:
- name: app
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
Kubernetes Secrets
Secrets store sensitive data (base64-encoded, not encrypted by default):
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
namespace: production
type: Opaque
data:
username: YWRtaW4= # base64 of "admin"
password: cEBzc3cwcmQ= # base64 of "p@ssw0rd"
host: bXlkYi5jbHVzdGVyLmFiYzEyMy51cy1lYXN0LTEucmRzLmFtYXpvbmF3cy5jb20=
EKS Secrets Encryption with KMS
By default, Kubernetes Secrets are stored as base64 in etcd — not truly encrypted. Enable envelope encryption with AWS KMS:
aws eks create-cluster \
--name my-cluster \
--encryption-config '[{
"resources": ["secrets"],
"provider": {"keyArn": "arn:aws:kms:us-east-1:123456789:key/abc-def-123"}
}]'
Or enable on an existing cluster:
aws eks associate-encryption-config \
--cluster-name my-cluster \
--encryption-config '[{
"resources": ["secrets"],
"provider": {"keyArn": "arn:aws:kms:us-east-1:123456789:key/abc-def-123"}
}]'
AWS Secrets Manager Integration
For production, use AWS Secrets Manager instead of Kubernetes Secrets.
AWS Secrets and Configuration Provider (ASCP)
ASCP mounts secrets from AWS Secrets Manager as files in your pods:
Step 1 — Install the Secrets Store CSI Driver and ASCP:
helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts
helm install csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver \
--namespace kube-system \
--set syncSecret.enabled=true
helm repo add aws-secrets-manager https://aws.github.io/secrets-store-csi-driver-provider-aws
helm install secrets-provider aws-secrets-manager/secrets-store-csi-driver-provider-aws \
--namespace kube-system
Step 2 — Create a SecretProviderClass:
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: aws-secrets
namespace: production
spec:
provider: aws
parameters:
objects: |
- objectName: "prod/db-credentials"
objectType: "secretsmanager"
jmesPath:
- path: username
objectAlias: db-username
- path: password
objectAlias: db-password
secretObjects:
- secretName: db-credentials-k8s
type: Opaque
data:
- objectName: db-username
key: username
- objectName: db-password
key: password
Step 3 — Mount in Your Pod:
spec:
serviceAccountName: app-sa # IRSA or Pod Identity with SecretsManager access
containers:
- name: app
volumeMounts:
- name: secrets
mountPath: /mnt/secrets
readOnly: true
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials-k8s
key: username
volumes:
- name: secrets
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: aws-secrets
External Secrets Operator
ESO syncs secrets from AWS Secrets Manager / Parameter Store into Kubernetes Secrets automatically:
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets \
--namespace external-secrets --create-namespace
Create a SecretStore
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: aws-secrets-store
namespace: production
spec:
provider:
aws:
service: SecretsManager
region: us-east-1
auth:
jwt:
serviceAccountRef:
name: external-secrets-sa # IRSA-annotated SA
Create an ExternalSecret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-store
kind: SecretStore
target:
name: db-credentials
data:
- secretKey: username
remoteRef:
key: prod/db-credentials
property: username
- secretKey: password
remoteRef:
key: prod/db-credentials
property: password
ESO automatically creates and updates the Kubernetes Secret db-credentials every hour.
ASCP vs External Secrets Operator
| Feature | ASCP | External Secrets Operator |
|---|---|---|
| How it works | CSI volume mount at pod startup | Controller syncs secrets as K8s Secrets |
| Refresh | On pod restart | Configurable interval |
| K8s Secret creation | Optional (syncSecret) | Always (creates K8s Secrets) |
| envFrom support | Via synced K8s Secret | Native (creates K8s Secrets) |
| Multi-provider | AWS only | AWS, GCP, Azure, Vault, etc. |
| Best for | Single-cloud AWS | Multi-cloud, frequent rotation |
AWS Parameter Store Integration
For non-secret configuration, use Parameter Store:
# External Secrets with Parameter Store
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: app-config
namespace: production
spec:
refreshInterval: 30m
secretStoreRef:
name: aws-param-store
kind: SecretStore
target:
name: app-config
data:
- secretKey: api_url
remoteRef:
key: /prod/api/url
- secretKey: feature_flag
remoteRef:
key: /prod/features/new-ui
Best Practices
- Enable KMS encryption for Kubernetes Secrets at the cluster level
- Use AWS Secrets Manager for production secrets (rotation, audit, cross-account)
- Use IRSA or Pod Identity for Secrets Manager access — never store AWS credentials in Secrets
- Separate config from secrets — ConfigMaps for non-sensitive, Secrets Manager for sensitive
- Set up secret rotation in AWS Secrets Manager and use ESO with a refresh interval
- Never commit secrets to Git — use External Secrets Operator for GitOps workflows
- Prefer volume mounts over environment variables for sensitive data (env vars appear in
kubectl describe)