Keeping the State of Apps Part 2: Introduction to Secrets

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:

  1. Docker-registry – Represents the credentials used to authenticate to a container registry
  2. Generic/Opaque – Represents literal values from different sources
  3. 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

Seyi Ewegbemi

Seyi Ewegbemi

Student Worker