Managing a secret on kubernetes

Most of the services we will be deploying on kubernetes are going to rely on having access to secrets to retrieve or push data to another service: Let's check how to work with the secrets on kubernetes

$ kubectl create secret
Create a secret using specified subcommand.

Available Commands:
  docker-registry Create a secret for use with a Docker registry
  generic         Create a secret from a local file, directory or literal value
  tls             Create a TLS secret

Usage:
  kubectl create secret [flags] [options]

Use "kubectl <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).

On kubernetes there's an object called "secret" that we can use to store secrets. We can, of course, create a secret using a yaml file but for demo purposes I think it makes more sense to create it imperatively using kubectl. We can push data to the secret using --from-literal (password from the command line) or --from-file (password is stored on a file). In any case the format would be --from-file=[key=]source/--from-literal=[key=]source

For exemple, to create a secret with username jordi.prats and password not_so_secret the command would be:

$ kubectl create secret generic democredentials \
                --from-literal=username=jordi.prats \
                --from-literal=password='not_so_secret'

Just to make it a little safer we could use a file to store the data so this way the secret won't be in the command history

$ kubectl create secret generic democredentials \
                --from-file=username=path/to/username_file
                --from-file=password=path/to/password_file

After creating the secret we can check it:

$ kubectl get secret democredentials
NAME              TYPE     DATA   AGE
democredentials   Opaque   2      69s

With describe we won't be able to actually see the secret:

$ kubectl describe secret democredentials
Name:         democredentials
Namespace:    kube-system
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
password:  13 bytes
username:  11 bytes

On the other hand, if we retrieve the secret as a yaml we will be able to see the secret:

$ kubectl get secret democredentials -o yaml
apiVersion: v1
data:
  password: bm90X3NvX3NlY3JldA==
  username: am9yZGkucHJhdHM=
kind: Secret
metadata:
  creationTimestamp: "2020-12-23T06:57:45Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:password: {}
        f:username: {}
      f:type: {}
    manager: kubectl-create
    operation: Update
    time: "2020-12-23T06:57:45Z"
  name: democredentials
  namespace: kube-system
  resourceVersion: "4576550"
  selfLink: /api/v1/namespaces/kube-system/secrets/democredentials
  uid: ba87853f-16c8-426a-b840-945bf40a6f0e
type: Opaque

On the data section of the yaml we can see that there are the fields we added to the secret (username/password) with it's value encoded using base64, we can retrieve the secrets by decoding these strings:

$ echo 'am9yZGkucHJhdHM=' | base64 -d
jordi.prats
$ echo 'bm90X3NvX3NlY3JldA==' | base64 -d
not_so_secret

We can also use the jsonpath to retrieve just the encoded string so we can use it on scripts more easily, for example:

$ kubectl get secret democredentials -o jsonpath="{.data.password}"
bm90X3NvX3NlY3JldA==
$ kubectl get secret democredentials -o jsonpath="{.data.password}" | base64 -d
not_so_secret

Posted on 23/12/2020