Creation of Secrets within Kubernetes

Secrets are means of storing and managing sensitive information such as passwords, tokens and keys. They are more secure then using ConfigMaps, which store the data in plain text but it should be noted they do not encrypt the data but encode it as Base64.

This post will describe 3 different ways of creating secrets, 2 of which do not rely on manual Base64 encoding and a method of building the manifest file with manually encoded strings.

Creating a Secret Using Files

We will create a secret using a couple of files that contain a username and password, which are in plain text.

salterje@k8s-master:~/YAML/secrets$ ls -lh
total 8.0K
-rw-rw-r-- 1 salterje salterje 23 Jul 12 15:11 password.txt
-rw-rw-r-- 1 salterje salterje  6 Jul 12 15:10 username.txt

salterje@k8s-master:~/YAML/secrets$ cat username.txt 
admin

salterje@k8s-master:~/YAML/secrets$ cat password.txt 
SuperSecretPassword123

salterje@k8s-master:~/YAML/secrets$

salterje@k8s-master:~/YAML/secrets$ kubectl create secret generic mysecret \
--from-file=username.txt \
--from-file=password.txt

This will create a secret object called mysecret which will have two fields contained within it.

The object can be checked using kubectl get secrets mysecret and more information can be gleaned by using kubectl describe secrets mysecret

salterje@k8s-master:~/YAML/secrets$ kubectl get secrets mysecret 
NAME       TYPE     DATA   AGE
mysecret   Opaque   2      11m

salterje@k8s-master:~/YAML/secrets$ kubectl describe secrets mysecret 
Name:         mysecret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password.txt:  23 bytes
username.txt:  6 bytes
salterje@k8s-master:~/YAML/secrets$ 

It can be seen that unlike a ConfigMap object the data is not displayed. Even looking at the output YAML file the original data is not displayed as plain text.

salterje@k8s-master:~/YAML/secrets$ kubectl get secrets mysecret -o yaml 

apiVersion: v1
data:
  password.txt: U3VwZXJTZWNyZXRQYXNzd29yZDEyMwo=
  username.txt: YWRtaW4K
kind: Secret
metadata:
  creationTimestamp: "2020-07-12T15:13:46Z"
  managedFields:
  name: mysecret
  namespace: default
  resourceVersion: "288441"
  selfLink: /api/v1/namespaces/default/secrets/mysecret
  uid: b7496c8b-3d58-490c-8156-6c124c0d6178
  

This shows that the original information has been replaced with Base64 strings.

Of course the original data can still be extracted by decoding the Base64 value to reveal the original string.

salterje@k8s-master:~/YAML/secrets$ echo "U3VwZXJTZWNyZXRQYXNzd29yZDEyMwo=" | base64 --decode
SuperSecretPassword123

salterje@k8s-master:~/YAML/secrets$ echo "YWRtaW4K" | base64 --decode
admin

It can be seen that the string containing the data to be decoded should be enclosed in quotes.

Creating a Secret Manually

The secret can also created directly by writing the manifest YAML directly and creating the object with a suitable create or apply command.

The first thing that needs to be done to allow this is to take the string to be encoded and convert it to Base64.

salterje@k8s-master:~/YAML/secrets$ echo -n "admin" | base64
YWRtaW4=
salterje@k8s-master:~/YAML/secrets$ echo -n "SuperSecretPassword123" | base64
U3VwZXJTZWNyZXRQYXNzd29yZDEyMw==

The following YAML manifest can then be created using the Base64 strings generated.

vi mysecret-manifest.yaml

apiVersion: v1
kind: Secret
metadata:
  name: mysecret2
type: Opaque
data: 
  username: YWRtaW4=
  password: U3VwZXJTZWNyZXRQYXNzd29yZDEyMw==
  
salterje@k8s-master:~/YAML/secrets$ kubectl apply -f mysecret-manifest.yaml
  

Creating the Manifest File Using the StringData Parameter

The previous methods relied on either importing the desired strings from external files or building a manifest file with pre-encoded Base64 strings. Another way is to combine the steps and allow Kubernetes to encode the strings entered into the manifest file automatically.

This is done using the StringData parameter.

salterje@k8s-master:~/YAML/secrets$ cat mysecret-manifest2.yaml 
apiVersion: v1
kind: Secret
metadata:
  name: mysecret3
type: Opaque
stringData:
    username: admin
    password: SuperSecretPassword123

To build the secret simply run the kubectl apply -f command with the manifest file.

salterje@k8s-master:~/YAML/secrets$ kubectl apply -f mysecret-manifest2.yaml 
secret/mysecret3 configured

salterje@k8s-master:~/YAML/secrets$ kubectl apply -f mysecret-manifest2.yaml 
secret/mysecret3 configured
salterje@k8s-master:~/YAML/secrets$ kubectl get secrets mysecret3
NAME        TYPE     DATA   AGE
mysecret3   Opaque   2      6m27s
salterje@k8s-master:~/YAML/secrets$ kubectl describe secrets mysecret3
Name:         mysecret3
Namespace:    default
Labels:       <none>
Annotations:  
Type:         Opaque

Data
====
password:  22 bytes
username:  5 bytes

Conclusions

Secrets are built in a similar way to ConfigMaps and can be used in similar ways. The data within the object is encoded as Base64 data that is a little more secure then using a ConfigMap object (although this should not be confused with encryption).

The choice of where to store the manifest files that are used to create the Secret will dictate if the data should be stored in plaintext or Base64.