K8s – Secrets

K8s Secrets allow you to store and manage your confidential data such as passwords , ssh keys , authentication tokens separately in a cluster level object that the PODs can fetch for their usage at the time of deployment.

  • Secret being an cluster level API object, provides a safer place and the ability to apply better access control
    • Better compared to hard coding such data in Pod definition or in a container image
    • Allows you to manage your confidential from a central location.
    • We can apply policies to restrict user access to view the secrets
  • We can apply data encryption on the secret data stored on ETCD.
  • It works very similar to ConfigMap and you can access the data as env variables or volumes.
  • It stores data in in-memory, tmpfs volumes at Node level.
    • Thus if a node crashes , neither the node nor the associated containers hold on to the confidential data.

Creating Secrets

Using ‘create secret command

Similar to ConfigMaps we can use ‘create secret’ command to create the key value pairs using :

  • from-literal : Literal key becomes key & literal value becomes value
  • from-file : File name (or the file-key, if specified) becomes the key and the content becomes the value
  • from-env-file : Each entry in side the file creates a literal value.

The following is an example secret being created using two literals(run this on a K8s cluster, say a minikube) :

# my-db-secrete using --from-literal 

kubectl create secret generic my-db-secret \
--from-literal=username='admin' \
--from-literal=password='pa$sw@rd1)%'

The resultant secrete can be retrieved using :

kubectl get secret my-db-secret -o yaml

The secrete in the output would look as below :

apiVersion: v1
data:
  password: cGEkc3dAcmQxKSU=
  username: YWRtaW4=
kind: Secret
metadata:
  creationTimestamp: "2020-06-30T13:32:40Z"
  name: my-db-secret
  namespace: default
  resourceVersion: "1016"
  selfLink: /api/v1/namespaces/default/secrets/my-db-secret
  uid: b17cf73b-dbeb-4a7d-9b6b-14ac8649d4ae
type: Opaque

As we can see the values are shown encrypted with Base64 encryption. This is the default encryption and you can change the encryption using K8s EncryptionConfiguration .

Using the secret inside a POD

Again the usage is also very similar to ConfigMaps.

Import as Env variables

Let us use the following POD to import the ‘my-db-secret’ created above into the env variables :

secret-test-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: secret-test-pod
spec:
  containers:
    - name: test-container
      image: k8s.gcr.io/echoserver:1.4
      envFrom:
      - secretRef:
          name: my-db-secret

Follow the steps for testing :

# Step - 1 : Create the secret my-db-secret

kubectl create secret generic my-db-secret \
--from-literal=username='admin' \
--from-literal=password='pa$sw@rd1)%'

#Step 2: Create the pod  and check the status
kubectl apply -f secret-test-pod.yaml

kubectl get pod,secret -o wide

#Step 3: When the pod is running , 
#              log in to its container shell and check the env variables
kubectl exec -it secret-test-pod -- /bin/bash

printenv

In the output, you should find the following two environment variables:

password=pa$sw@rd1)%
username=admin

Summary of importing Secret as Env variables

  • Each literal and each file entry in a secret, is imported as a separate environment variable
  • For literals, the value of the variable is the literal’s value
  • For the files, the value of the variable is the content of the file.

The above example is for importing all the keys in a secret. The comparison of the syntax to read few particular keys is as shown below :

All entries in a Secret

      envFrom:
      - secretRef:
          name: my-db-secret

Specific entries in a secret

env:
      - name: USERNAME
        valueFrom:
          secretKeyRef:
            name: my-db-secret
            key: username
      - name: PASSWORD
        valueFrom:
          secretKeyRef:
            name: my-db-secret
            key: password

Import into volume

secret-vol-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: secret-vol-pod
spec:
  containers:
  - name: test-container
    image: k8s.gcr.io/echoserver:1.4
    volumeMounts:
    - name: secret-volume
      readOnly: true
      mountPath: "/secret-volume"		  
  volumes:
  - name: secret-volume
    secret:
      secretName: my-db-secret

The syntax for importing secrets has been highlighted in the above pod definition.

Let us follow the below steps to try this out with an example:

# Step - 1 : Create the sample  secret 'my-db-secret'
kubectl create secret generic my-db-secret \
--from-literal=username='admin' \
--from-literal=password='pa$sw@rd1)%'

#Step 2: Create the pod  and check the status
kubectl apply -f secret-test-pod.yaml
kubectl get pod,secret -o wide

#Step 3: When the pod is running , 
#              log in to its container shell and move to the mount path
kubectl exec -it secret-test-pod -- /bin/bash

cd secret-volume

The contents of the mount path would be as follows:

#The mount path has two link file for two literal entries 
root@secret-vol-pod:/secret-volume# ls -l
total 0
lrwxrwxrwx 1 root root 15 Jun 30 15:48 password -> ..data/password
lrwxrwxrwx 1 root root 15 Jun 30 15:48 username -> ..data/username

#Content of username - its literal value in secret
root@secret-vol-pod:/secret-volume# cat username
admin

#Content of password- its literal value in secret
root@secret-vol-pod:/secret-volume# cat password
pa$sw@rd1)%

Summary of importing a Secret using a volume

  • Each data key in the secret will be listed as a linked file under the mount path.
  • For literals – the content of the linked file would be the literal’s value
  • For files – the content of the linked file would be the content of the file in the secret

The above example imports all the keys in a secret into a volume. Comparison of the syntax to import only few specific keys is as follows:

For all keys in a secret

volumes:
  - name: secret-volume
    secret:
      secretName: my-db-secret      

For specific keys in a secret

volumes:
  - name: secret-volume
    secret:
      secretName: my-db-secret
      items:
      - key: username
        path: USERNAME
      - key: password
        path: PASSWORD