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.
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 :
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:
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
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