Mounting AWS Secrets Manager secret on Kubernetes Pod
Now that we have a secret stored in AWS Secrets Manager and synchronized with a Kubernetes Secret, let's mount it inside the Pod. First, we should examine the catalog
Deployment and the existing Secrets in the catalog
namespace.
Currently, the catalog
Deployment accesses database credentials from the catalog-db
secret via environment variables:
DB_USER
DB_PASSWORD
- name: DB_USER
valueFrom:
secretKeyRef:
key: username
name: catalog-db
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: catalog-db
The catalog
Deployment currently has no additional volumes
or volumeMounts
except for an emptyDir
mounted at /tmp
:
- emptyDir:
medium: Memory
name: tmp-volume
- mountPath: /tmp
name: tmp-volume
Let's modify the catalog
Deployment to use the secret stored in AWS Secrets Manager as the source for credentials:
- Kustomize Patch
- Deployment/catalog
- Diff
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../../../base-application/catalog
patches:
- path: deployment.yaml
- path: serviceaccount.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/created-by: eks-workshop
app.kubernetes.io/type: app
name: catalog
namespace: catalog
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/component: service
app.kubernetes.io/instance: catalog
app.kubernetes.io/name: catalog
template:
metadata:
annotations:
prometheus.io/path: /metrics
prometheus.io/port: "8080"
prometheus.io/scrape: "true"
labels:
app.kubernetes.io/component: service
app.kubernetes.io/created-by: eks-workshop
app.kubernetes.io/instance: catalog
app.kubernetes.io/name: catalog
spec:
containers:
- env:
- name: DB_USER
valueFrom:
secretKeyRef:
key: username
name: catalog-secret
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: catalog-secret
envFrom:
- configMapRef:
name: catalog
image: public.ecr.aws/aws-containers/retail-store-sample-catalog:0.4.0
imagePullPolicy: IfNotPresent
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 3
name: catalog
ports:
- containerPort: 8080
name: http
protocol: TCP
readinessProbe:
httpGet:
path: /health
port: 8080
periodSeconds: 5
successThreshold: 3
resources:
limits:
memory: 512Mi
requests:
cpu: 250m
memory: 512Mi
securityContext:
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
volumeMounts:
- mountPath: /etc/catalog-secret
name: catalog-secret
readOnly: true
- mountPath: /tmp
name: tmp-volume
securityContext:
fsGroup: 1000
serviceAccountName: catalog
volumes:
- csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: catalog-spc
name: catalog-secret
- emptyDir:
medium: Memory
name: tmp-volume
- name: DB_USER
valueFrom:
secretKeyRef:
key: username
- name: catalog-db
+ name: catalog-secret
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
key: password
- name: catalog-db
+ name: catalog-secret
envFrom:
- configMapRef:
name: catalog
image: public.ecr.aws/aws-containers/retail-store-sample-catalog:0.4.0
[...]
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
volumeMounts:
+ - mountPath: /etc/catalog-secret
+ name: catalog-secret
+ readOnly: true
- mountPath: /tmp
name: tmp-volume
securityContext:
fsGroup: 1000
serviceAccountName: catalog
volumes:
+ - csi:
+ driver: secrets-store.csi.k8s.io
+ readOnly: true
+ volumeAttributes:
+ secretProviderClass: catalog-spc
+ name: catalog-secret
- emptyDir:
medium: Memory
name: tmp-volume
We'll mount the AWS Secrets Manager secret using the CSI driver with the SecretProviderClass we validated earlier at the /etc/catalog-secret
mountPath inside the Pod. This will trigger AWS Secrets Manager to synchronize the stored secret contents with Amazon EKS and create a Kubernetes Secret that can be consumed as environment variables in the Pod.
Let's verify the changes made in the catalog
namespace.
The Deployment now has a new volume
and corresponding volumeMount
that uses the CSI Secret Store Driver and is mounted at /etc/catalog-secrets
:
- csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: catalog-spc
name: catalog-secret
- emptyDir:
medium: Memory
name: tmp-volume
- mountPath: /etc/catalog-secret
name: catalog-secret
readOnly: true
- mountPath: /tmp
name: tmp-volume
Mounted Secrets provide a secure way to access sensitive information as files inside the Pod's container filesystem. This approach offers several benefits including not exposing secret values as environment variables and automatic updates when the source Secret is modified.
Let's examine the contents of the mounted Secret inside the Pod:
eks-workshop-catalog-secret password username
{"username":"catalog_user", "password":"default_password"}
catalog_user
default_password
The mountPath /etc/catalog-secret
contains three files:
eks-workshop-catalog-secret
: Contains the complete secret value in JSON formatpassword
: Contains the password value filtered by jmesPathusername
: Contains the username value filtered by jmesPath
The environment variables are now sourced from the newly created catalog-secret
, which was automatically created by the SecretProviderClass via the CSI Secret Store driver:
- name: DB_USER
valueFrom:
secretKeyRef:
key: username
name: catalog-secret
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: catalog-secret
NAME TYPE DATA AGE
catalog-db Opaque 2 15h
catalog-secret Opaque 2 43s
We can confirm the environment variables are set correctly in the running pod:
We now have a Kubernetes Secret fully integrated with AWS Secrets Manager that can leverage secret rotation, a best practice for secrets management. When a secret is rotated or updated in AWS Secrets Manager, we can roll out a new version of the Deployment allowing the CSI Secret Store driver to synchronize the Kubernetes Secret contents with the updated value.