The AWS Secrets Manager CSI driver doesn’t actually sync secrets into EKS pods; it mounts them as files in a read-only filesystem.
Let’s see it in action. Imagine you have a secret in AWS Secrets Manager named my-app/db-credentials. It contains JSON like this:
{
"username": "admin",
"password": "supersecretpassword"
}
You want this secret available inside an EKS pod. First, you need the Secrets Manager CSI driver installed in your EKS cluster. You can usually do this via the AWS EKS add-ons or by deploying the driver’s YAML directly.
Next, you define a SecretProviderClass in Kubernetes. This tells the CSI driver which secret to fetch and how to present it.
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: aws-secretsmanager-reader
spec:
provider: aws
parameters:
objects: |
- objectName: "my-app/db-credentials"
objectType: "secretsmanager"
jmesPath:
- path: "username"
objectAlias: "db-user"
- path: "password"
objectAlias: "db-password"
The objectName is the ARN or name of your secret in Secrets Manager. objectType: "secretsmanager" is self-explanatory. The jmesPath is where the magic happens: it lets you extract specific fields from a JSON secret. path is the JMESPath expression to get the value, and objectAlias is the filename that will be created inside the pod.
Now, you mount this SecretProviderClass into your pod’s specification using a persistent volume.
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
spec:
containers:
- name: my-app-container
image: ubuntu
command: ["sleep", "3600"]
volumeMounts:
- name: secrets-store-inline
mountPath: "/mnt/secrets-store"
readOnly: true
volumes:
- name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: "aws-secretsmanager-reader"
When this pod starts, the CSI driver, running as a DaemonSet on your EKS nodes, will:
- Detect the volume mount requesting the
aws-secretsmanager-readerSecretProviderClass. - Use the AWS SDK configured on the node (via IAM roles, typically an instance profile) to call the Secrets Manager API (
secretsmanager:GetSecretValue). - Parse the returned JSON secret using the specified JMESPaths.
- Create a temporary, read-only filesystem (often using
tmpfs) on the node. - Write the extracted values into files within that temporary filesystem, named according to the
objectAlias(db-user,db-password). - Mount this temporary filesystem into the pod at
/mnt/secrets-store.
Inside the my-app-container, you can then cat /mnt/secrets-store/db-user and cat /mnt/secrets-store/db-password to get your credentials.
The core problem this solves is securely injecting secrets into pods without baking them into container images or exposing them as plaintext Kubernetes Secrets objects, which are typically base64 encoded and not encrypted at rest by default. The CSI driver leverages AWS IAM for authentication and AWS Secrets Manager for storage, offering a more robust security posture.
A common misconception is that the CSI driver syncs secrets into Kubernetes Secret objects. While it can be configured to do that (using the secretObjects field in the SecretProviderClass), its primary and most powerful use case is direct mounting, which bypasses Kubernetes Secrets entirely for the actual secret data. This means the secret values never touch etcd, enhancing security.
The most surprising thing is how the CSI driver leverages the node’s IAM role for authorization to AWS Secrets Manager. You don’t need to configure separate AWS credentials within the pod or even provide them to the CSI driver’s deployment itself. The driver running on the node assumes the node’s IAM role, making the integration seamless and secure.
The next hurdle you’ll likely encounter is managing secret rotation and ensuring your applications can gracefully handle updated secrets without restarting.