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 cat
command:
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!
Learn More
- Visit the official Kubernetes website for more resources on Kubernetes Secrets
- Learn more about Kubernetes Secrets practices here