Sync with native Kubernetes secrets

This workshop has been deprecated and archived. The new Amazon EKS Workshop is now available at www.eksworkshop.com.

This section covers the following use cases.

  1. Fetch values from the individual keys of the JSON formatted secrets and mount them as separate files.
  2. Sync secrets from the mounted volumes to native Kubernetes secrets object.
  3. Use Kubernetes standard feature to set up environment variables from the Kubernetes secrets.

Create SecretProviderClass to extract key-value pairs

Let’s create a SecretProviderClass custom resource and use jmesPath field in the spec file. Use of jmesPath allows extracting specific key-value from a JSON-formatted secret. It is a provider-specific feature from ASCP.

secretObjects spec section allows specifying the Kubernetes native secret structure synced from the objects: extracted from the JSON formatted secret using jmesPath. The feature is provided by the standard Secret Store CSI Driver.

cat << EOF > nginx-deployment-spc-k8s-secrets.yaml
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: nginx-deployment-spc-k8s-secrets
spec:
  provider: aws
  parameters: 
    objects: |
      - objectName: "DBSecret_eksworkshop"
        objectType: "secretsmanager"
        jmesPath:
          - path: username
            objectAlias: dbusername
          - path: password
            objectAlias: dbpassword
  # Create k8s secret. It requires volume mount first in the pod and then sync.
  secretObjects:                
    - secretName: my-secret-01
      type: Opaque
      data:
        #- objectName: <objectName> or <objectAlias> 
        - objectName: dbusername
          key: db_username_01
        - objectName: dbpassword
          key: db_password_01
EOF

Create custom resource.

kubectl apply -f nginx-deployment-spc-k8s-secrets.yaml

kubectl get SecretProviderClass nginx-deployment-spc-k8s-secrets

The output indicates the resource nginx-deployment-spc-k8s-secrets created successfully.


NAME                               AGE
nginx-deployment-spc-k8s-secrets   10s

Create pod mount secrets volumes and set up Environment variables.

Configure a pod to mount volumes for individually extracted key-value pairs from the secrets. Once the pod is created with secrets volume mounts, the Secrets Store CSI Driver then creates and syncs Kubernetes secret object my-secret-01. The pod then be able to populate Environment variables from the Kubernetes secret.

cat << EOF > nginx-deployment-k8s-secrets.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-k8s-secrets
  labels:
    app: nginx-k8s-secrets
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-k8s-secrets
  template:
    metadata:
      labels:
        app: nginx-k8s-secrets
    spec:
      serviceAccountName: nginx-deployment-sa
      containers:
      - name: nginx-deployment-k8s-secrets
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
          - containerPort: 80
        volumeMounts:
          - name: secrets-store-inline
            mountPath: "/mnt/secrets"
            readOnly: true
        env:
          - name: DB_USERNAME_01
            valueFrom:
              secretKeyRef:
                name: my-secret-01
                key: db_username_01
          - name: DB_PASSWORD_01
            valueFrom:
              secretKeyRef:
                name: my-secret-01
                key: db_password_01
      volumes:
        - name: secrets-store-inline
          csi:
            driver: secrets-store.csi.k8s.io
            readOnly: true
            volumeAttributes:
              secretProviderClass: nginx-deployment-spc-k8s-secrets
EOF

Create the deployment and verify the creation of pods.

kubectl apply -f nginx-deployment-k8s-secrets.yaml
sleep 2
kubectl get pods -l "app=nginx-k8s-secrets"

Verify the result

Get a shell prompt within the pod by running the following commands. Verify the secret mounted as separate files for each extracted key-value pair and corresponding environment variables set as well.

export POD_NAME=$(kubectl get pods -l app=nginx-k8s-secrets -o jsonpath='{.items[].metadata.name}')
kubectl exec -it ${POD_NAME} -- /bin/bash

Wait for the root shell prompt within the pod. Run the following set of commands and watch the output in the pod’s shell.

export PS1='# '
cd /mnt/secrets
ls -l   #--- List mounted secrets

cat dbusername; echo  
cat dbpassword; echo
cat DBSecret_eksworkshop; echo

env | grep DB    #-- Display two ENV variables set from the secret values
sleep 2
exit

The output shows the information as displayed here. The last exit command in the shell window exits from the pod’s shell.


# cd /mnt/secrets
# ls -l   #--- List mounted secrets
total 12
-rw-r--r-- 1 root root 45 Nov 22 01:56 DBSecret_eksworkshop
-rw-r--r-- 1 root root 12 Nov 22 01:56 dbpassword
-rw-r--r-- 1 root root  3 Nov 22 01:56 dbusername
# 
# cat dbusername; echo  
foo
# cat dbpassword; echo
super-sekret
# cat DBSecret_eksworkshop; echo
{"username":"foo", "password":"super-sekret"}
# 
# env | grep DB    #-- Display two ENV variables set from the secret values
DB_USERNAME_01=foo
DB_PASSWORD_01=super-sekret
# sleep 2

# exit
exit

Notice under the path /mnt/secrets key-values pairs extracted in separate files based on jmesPath specification. Files dbusername and dbpassword contains extracted values from the JSON formatted secret DBSecret_eksworkshop

Two Environment variables DB_USERNAME_01 and DB_PASSWORD_01 are set up respectively. These ENV vars mapped from the Kubernetes secrets object my-secret-01 created automatically by the CSI driver.

Confirm the presence of Kubernetes secrets. It was created automatically by the CSI driver during pod deployment.

kubectl describe secrets my-secret-01

NAME           TYPE     DATA   AGE
my-secret-01   Opaque   2      14m
meharwal@147dda3bc928 tmp % kubectl describe secrets my-secret-01
Name:         my-secret-01
Namespace:    default
Labels:       secrets-store.csi.k8s.io/managed=true
Annotations:  <none>

Type:  Opaque

Data
====
db_password_01:  12 bytes
db_username_01:  3 bytes