Working with secrets

Kubernetes secrets manage information in key-value formats with the value encoded. With secrets, users don't have to set values in the configuration file or type them in CLI. When secrets are used properly, they can reduce the risk of credential leak and make our resource configurations more organized.

Currently, there are three types of secret:

Opaque is the default type. We will put service account tokens and the authentication of Docker in the remark part.

Getting ready

Before using our credentials with secrets, some precautions must be taken First, secrets have a 1 MB size limitation. It works fine for defining several key-value pairs in a single secret. But, be aware that the total size should not exceed 1 MB. Next, secret acts like a volume for containers, so secrets should be created prior to dependent pods.

How to do it…

We can only generate secrets by using configuration files. In this recipe, we will deliver a simple template file and focus on the functionality. For various template designs, please take a look at the Working with configuration files recipe in Chapter 3, Playing with Containers.

Creating a secret

The configuration file of secrets contains secret type and data:

// A simple file for configuring secret
# cat secret-test.json
{
  "kind": "Secret",
  "apiVersion": "v1",
  "metadata": {
    "name": "secret-test"
  },
  "type": "Opaque",
  "data": {
    "username": "YW15Cg==",
    "password": " UGEkJHcwcmQhCg=="
  }
}

The secret type Opaque is the default one, which simply indicates that the data is not shown. The other types, service account token and Docker authentication, are applied when using the values kubernetes.io/service-account-token and kubernetes.io/dockercfg at the type item stage, respectively.

The data username and password are customized keys. Their corresponding values are base64-encoded string. You can get your encoded value through these pipe commands:

# echo "amy" | base64
YW15Cg==

The resource annotation and management of secrets is similar to other resource types. Feel free to create a secret and check its status by using common subcommands:

# kubectl create -f secret-test.json
secret "secret-test" created
# kubectl get secret
NAME          TYPE      DATA      AGE
secret-test   Opaque    2         39s
# kubectl describe secret secret-test
Name:    secret-test
Namespace:  default
Labels:    <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  10 bytes
username:  4 bytes

As you can see, although secret hides the information, we can get the amount of data, the data name and also the size of the value.

Picking up secret in the container

In order to let the pod get the secret information, secret data is mounted as a file in the container. The key-value pair data will be shown in plain-text file format, which takes a key name as the file name and the decoded value as the file content. Therefore, we create the pod by configuration file, where the container's mounting volume is pointed to secret:

# cat pod-secret.json
{
  "kind": "Pod",
  "apiVersion": "v1",
  "metadata": {
    "name": "pod-with-secret"
  },
  "spec": {
    "volumes": [
      {
        "name": "secret-volume",
        "secret": {
          "secretName": "secret-test"
        }
      }
    ],
    "containers": [
      {
  "name": "secret-test-pod",
        "image": "nginx",
        "volumeMounts": [
          {
            "name": "secret-volume",
            "readOnly": true,
            "mountPath": "/tmp/secret-volume"
          }
        ]
      }
    ]
  }
}

For the previous template, we defined a volume called secret-volume which includes physical files with the content of the secret secret-test; the containers' mounting point is also defined along with the location, where to put secret files, and bound with secret-volume. In this case, the container could access secrets in its local file system by using /tmp/secrets/<SECRET_KEY>.

To verify the content is decrypted for the usage of the container program, let's take a look at the specific container on the node:

// login to node and enable bash process with new tty
# docker exec -it <CONTAINER_ID> bash
root@pod-with-secret:/# ls /tmp/secrets/
password  username
root@pod-with-secret:/# cat /tmp/secrets/password
Pa$$w0rd!
root@pod-with-secret:/# cat /tmp/secrets/username
amy

Deleting a secret

Secret, like other resources, can be stopped by the subcommand delete. Both methods, deleting according to configuration file or deleting by resource name are workable:

# kubectl delete -f secret-test.json
secret "secret-test" deleted

How it works…

In order to reduce the risk of leaking the secrets' content, the Kubernetes system never saves the data of secrets on disk. Instead, secrets are stored in the memory. For a more accurate statement, the Kubernetes API server pushes secret to the node on which the demanded container is running. The node stores the data in tmpfs, which will be flashed if the container is destroyed.

Go and check the node, which has container with secrets running on it:

// check the disk
df -h --type=tmpfs
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           920M     0  920M   0% /dev/shm
tmpfs           920M   17M  903M   2% /run
tmpfs           920M     0  920M   0% /sys/fs/cgroup
tmpfs           184M     0  184M   0% /run/user/2007
tmpfs           920M  8.0K  920M   1% /var/lib/kubelet/pods/2edd4eb4-b39e-11e5-9663-0200e755981f/volumes/kubernetes.io~secret/secret-volume

Furthermore, I suggest that you avoid creating a large-size secret or many small-size secrets. Since secrets are kept in the memory of nodes, reducing the total size of secrets could help to save resources and maintain good performance.

There's more…

In the previous sections, secret is configured in the default service account. The service account can make processes in containers in contact with the API server. You could have different authentication by creating different service accounts.

Let's see how many service accounts we currently have:

$ kubectl get serviceaccounts
NAME          SECRETS   AGE
default       0         18d

Kubernetes will create a default service account. Let's see how to create our own one:

# example of service account creation
$ cat serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: test-account

# create service account named test-account
$ kubectl create -f serviceaccount.yaml
serviceaccount "test-account" created

After creation, let's list the accounts by kubectl:

$ kubectl get serviceaccounts
NAME           SECRETS   AGE
default        0         18d
test-account   0         37s

We can see there is a new service account named test-account in the list now.

Each service account could have its own API token, image pull secrets and mountable secrets.

Similarly, we could delete the service account by using kubectl:

$ kubectl delete serviceaccount test-account
serviceaccount "test-account" deleted

On the other hand, Docker authentication can also be saved as a secret data for pulling images. We will discuss the usage in Working with the private Docker registry recipe in Chapter 5, Building a Continuous Delivery Pipeline.

See also

  • The Working with configuration files recipe in Chapter 3, Playing with Containers
  • The Moving monolithic to microservices, Working with the private Docker registry recipes in Chapter 5, Building a Continuous Delivery Pipeline
  • The Advanced settings in kubeconfig recipe in Chapter 7, Advanced Cluster Administration
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset