Amazon EKS — ConfigMaps and Secrets

3 minute read

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

  1. Enable KMS encryption for Kubernetes Secrets at the cluster level
  2. Use AWS Secrets Manager for production secrets (rotation, audit, cross-account)
  3. Use IRSA or Pod Identity for Secrets Manager access — never store AWS credentials in Secrets
  4. Separate config from secrets — ConfigMaps for non-sensitive, Secrets Manager for sensitive
  5. Set up secret rotation in AWS Secrets Manager and use ESO with a refresh interval
  6. Never commit secrets to Git — use External Secrets Operator for GitOps workflows
  7. Prefer volume mounts over environment variables for sensitive data (env vars appear in kubectl describe)

Updated: