Kubernetes has an integrated pattern for decoupling configuration from application or container to make it portable and make its management flexible. This inbuilt pattern allows application externalisation, as well as giving the application components autonomy from the container image.
Application configuration with Kubernetes makes use of two Kubernetes objects: Secrets for sensitive data and ConfigMaps for non sensitive data. These objects are used for the external configuration of individual key-pair values by using them as either environment variables or files inside a running container in a Pod.
In this part of our Kubernetes 101 series, we will continue with the data preservation by bringing Kubernetes Secrets into the game. The below topics will be covered in this part while ConfigMaps and its functionalities will be covered in the next part of our series.
- How to configure your application
- Using files for the configuration of your application
- Using environment variables for the configuration of your application
- How to make Kubernetes meta info available in your application
What Is a Kubernetes Secret
A Secret in Kubernetes is a Kubernetes object used to secure and hold sensitive data. It protects the sensitive data like passwords, tokens, ssh & API keys, OAuth credentials etc. from unauthorised access and reduces the risk of exposing sensitive data during Pod creation.
It has a maximum size of 1MB, and it can be deployed into a Pod as volume, environment variables or kubelet. During Pod creation, putting sensitive information like usernames, passwords, tokens and keys as plain text in the YAML file is not the best configuration practice in Kubernetes, which is where Kubernetes Secrets come in.
Types of Kubernetes Secrets
There are three types of Kubernetes Secrets:
- Docker-registry – Represents the credentials used to authenticate to a container registry
- Generic/Opaque – Represents literal values from different sources
- Tls – Represents a certificate-based Secret
Creating a Kubernetes Secret
Kubernetes Secrets can be created in declarative and imperative ways. In the part two of this series, we discuss extensively the declarative and imperative ways of creating Kubernetes objects.
Creating a Secret Imperatively and Declaratively
The imperative way of creating a Secret entails passing the commands as flags on the command line using the kubectl command-line tool. The declarative way, on the other hand, involves the creation of Secret configuration data in a manifest file which can either be in YAML or JSON syntax.
The steps below will show you how to create a Secret and inject the Secret into a Pod. You need a running Kubernetes cluster for this exercise together with a kubectl command-line tool. (You can easily create a Kubernetes cluster on any environment with KubeOne. Check the Getting Started for instructions. Alternatively, you can use the Kubernetes playground for practising purposes.)
Imperative Method by Using Kubectl:
Step 1: Create a file to store your username and password on your local machine:
$ echo -n 'admin' > ./username.txt $ echo -n '1t3b2e4f89yz' > ./password.txt
Step 2: Create the Secret:
$ kubectl create secret generic my-secret --from-file=./username.txt --from-file=./password.txt\ secret/my-secret created
Step 3: Check the created Secret:
$ kubectl get secrets my-secret NAME TYPE DATA AGE my-secret Opaque 2 25s
A Secret with the name my-secret is created with Opaque as the Secret type. The data column shows the number of data stored in the Secret, which are 2 (username and password values) in our example.
Step 4: To see the details of the Secret:
$kubectl describe secrets my-secret Name: my-secret ## Name of the Secret as declared in the YAML file Namespace: default ## The NameSpace where the Secret is created Labels: <none> Annotations: <none> Type: Opaque Data ## The file where the secret will be stored. ==== password.txt: 12 bytes ## The secured data username.txt: 5 bytes ## The secured data
Declarative or Manual Method of Creating a Secret
Step 1: Encode the data by converting it to base 64.
$echo -n 'admin' | base64 Output: YWRtaW4= $echo -n '1t3b2e4f89yz ' | base64 Output: MXQzYjJlNGY4OXl6
Step 2: Create a manifest YAML file:
$ vim secret.yaml
Step 3: Copy, paste and save the below configuration into your manifest YAML file.
apiVersion: v1 kind: Secret metadata: name: mysecret data: username: YWRtaW4= ## The encoded data password: MXQzYjJlNGY4OXl6
Step 4: Create the Secret using kubectl create:
$ kubectl create -f secret.yaml secret/mysecret created
Step 5: Check the status of the Secret:
$ kubectl get secret mysecret NAME TYPE DATA AGE mysecret Opaque 2 6s
Step 6: Check the description of the Secret:
$ kubectl describe secret mysecret ## Where mysecret is the name of the secret. Name: mysecret Namespace: default Labels: <none> Annotations: <none> Type: Opaque Data ==== password: 12 bytes username: 5 bytes
How to Decode a Secret
You can decode the Secret (username and password) stored in the application above even after it has been encoded using base 64.
To decode a Secret, copy any of the values from the two fields (username or password) and use the command
echo 'Secret Value' | base64 --decode to decode it. You can find these values in the Secret manifest YAML file by running the command
kubectl get secret mysecret -o yaml
Follow the below steps to decode the created Secret above:
Step 1: Get the encoded value using the command:
$ kubectl get secret mysecret -o yaml
The output will look like this:
apiVersion: v1 data: password: MXQzYjJlNGY4OXl6 username: YWRtaW4= kind: Secret metadata: creationTimestamp: "2020-08-20T15:23:09Z" managedFields: apiVersion: v1 fieldsType: FieldsV1
Step 2: Copy any of the values and decode it with the below command. In this example, we will decode the password field.
$ echo 'MXQzYjJlNGY4OXl6' | base64 --decode 1t3b2e4f89yz
If you look at the output, you will see that it is the same with the password value that was encoded earlier under this topic.
How to Mount a Secret Into a Container in a Pod
You can mount a Secret into a Container in a Pod using volume and volumeMounts as files or environment variables. We will walk you through how to use these two methods.
Mounting a Secret as a File in a Pod
You can mount a Secret into a running container in a Pod using files by following the below steps.
The Secret we created earlier will be used for this exercise.
Now that you have your Secret created on the cluster, the next step is to create a Pod that will reference the Secret.
Step 1: Create a file using vim editor.
$ vim secret-pod.yaml
Step 2: Copy, paste, and save the below manifest file and exit the terminal.
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: name: mycontainer image: nginx volumeMounts: name: foo mountPath: /opt/foo volumes: name: foo secret: secretName: mysecret
Step 3: Create the Pod:
$ kubectl create -f secret-pod.yaml pod/mypod created
Step 4: Check the Pod status:
$kubectl get pods mypod $kubectl get pods mypod NAME READY STATUS RESTARTS AGE mypod 1/1 Running 0 19s
Step 5: Exec into the container to check if you can access the Secret:
$ kubectl exec -ti mypod -- bin/bash root@mypod:/#
Step 6: Change into the mountPath directory(/opt/foo) from the Pod manifest and check the file in the folder.
$ root@myapp:/# cd /opt/foo root@myapp:/opt/foo#
Step 7: You can open the file using
root@mypod:/opt/foo# cat username admin\ root@mypod:/opt/foo# cat password 1t3b2e4f89yz Type exit command to exit from the container. root@mypod:/opt/foo# exit master $
The Secret has successfully been injected into the container.
Mount a Secret as Environment Variables in a Pod
The below steps will guide you on how to inject a Secret into a Pod using environment variables. You need to first create the Secret before creating the Pod. Then reference the Secret in the Pod by adding the environment variable block, which contains properties such as name, valueFrom among others. We will assume that the Secret has been created. Now, you need to create the Pod.
Create the Pod:
Step 1: Edit the Pod manifest file by removing the volume block and replace it with the environment variables block as it is shown below.
env: name: USERNAME valueFrom: secretKeyRef: name: mysecret key: username name: PASSWORD valueFrom: secretKeyRef: name: mysecret key: password restartPolicy: Never
The complete manifest file will look like this:
apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: name: mycontainer image: nginx env: name: USERNAME valueFrom: secretKeyRef: name: mysecret key: username name: PASSWORD valueFrom: secretKeyRef: name: mysecret key: password restartPolicy: Never
Step 2: Create the Pod:
$ kubectl create -f secret-pod.yaml pod/mypod created
Step 3: Check the Pod status:
$kubectl get pods mypod NAME READY STATUS RESTARTS AGE mypod 1/1 Running 0 19s
Step 4: Exec into the Pod to check if the Secret has already been injected into the Pod
$ kubectl exec -it mypod -- bin/bash root@mypod:/#
Step 5: Use echo command to display the username and password. If everything worked correctly, you should see the values of both the username and password inside the container.
$ root@mypod:/# echo $USERNAME $PASSWORD admin 1t3b2e4f89yz
To clean up, delete the Secret and the Pod using kubectl delete command.
$ kubectl delete pod mypod pod/mypod deleted
$ kubectl delete secret mysecret secret/mysecret deleted
Congratulations! you have successfully created a Secret and injected it into a Pod by mounting it into a container in a Pod using files and environment variables.
Next in our series, we will guide you through another Kubernetes object known as ConfigMaps which is similar to Kubernetes Secret. Please feel free to contact us with any questions you have on Secret or other Kubernetes objects!