Terminus
Create Kubernetes Secrets with `kubectl`

Create Kubernetes Secrets with `kubectl`

In Kubernetes, a Secret is an object that stores sensitive data for containers to use in the form of a key-value pair, such as a password, a token, or an access key.

The short answer

To create a Secret, you can use the [.inline-code]kubectl create secret generic[.inline-code] command as follows:

 $ kubectl create secret generic <secret_name>--from-literal <key>=<value>

Where:

  • [.inline-code]secret_name[.inline-code] is the name of the secret.
  • [.inline-code]key[.inline-code] is the name of the key (e.g. [.inline-code]password[.inline-code]).
  • [.inline-code]value[.inline-code] is the value of the key (e.g. [.inline-code]S!B\*d$zDsb=[.inline-code]).

For example:

 $ kubectl create secret generic demo-secret --from-literal dbPassword=p4ssw0rd --from-literal
dbUser=postgres

The above command will create a general-purpose secret called [.inline-code]demo-secret[.inline-code] with two keys [.inline-code]dbPassword[.inline-code] and [.inline-code]dbUser[.inline-code].

To view the secret in [.inline-code]yaml[.inline-code] format you can use the [.inline-code]kubectl get secret[.inline-code] command as follows:

 $ kubectl get secret demo-secret -o yaml
apiVersion: v1
data:
  dbPassword: cDRzc3cwcmQ=
  dbUser: cG9zdGdyZXM=
kind: Secret
metadata:
  creationTimestamp: "2023-08-24T14:44:01Z"
  name: demo-secret
  namespace: default
  resourceVersion: "1170"
  uid: 4b6953b3-081d-4fa0-870c-79cf01c3199e
type: Opaque

Note that these values are, by default, encoded into Base64, but you can easily retrieve a specific value and decode it using the following command:

 $ kubectl get secret demo-secret -o jsonpath='{.data.dbUser}' | base64 -d
postgres

Which is quite useful if, for example, you've installed a Helm chart that generates random passwords at installation and you need to retrieve these values in order to manually access the instance.

[#easily-recall-with-ai]Easily retrieve this command using Warp’s AI Command Search[#easily-recall-with-ai]

If you’re using Warp as your terminal, you can easily retrieve this command using the Warp AI Command Search feature:

Entering [.inline-code]k8s literal secret[.inline-code] in the AI Command Search will prompt a [.inline-code]kubectl[.inline-code] command that can then quickly be inserted into your shell by doing [.inline-code]CMD+ENTER[.inline-code].

Note that you can also recall the decode command by entering [.inline-code]k8s decode secret key[.inline-code].

[#creating-a-secret-from-a-file]Creating a Secret from a file[#creating-a-secret-from-a-file]

To create a Secret from a value contained in a regular file, you can use the [.inline-code]--from-file[.inline-code] flag as follows:

 $ kubectl create secret generic <secret_name> --from-file <file_path>

For example:

 $ echo "secret text file" > secret.txt
$ kubectl create secret generic secret-file --from-file secret.txt
secret/secret-file created

When creating a secret using a file, [.inline-code]kubectl[.inline-code] will use the filename as the default key and the file contents as the value.

To specify a different key, you can use the following syntax:

 $ kubectl create secret generic <secret_name> --from-file=<key_name>=<file_path>

For example:

 $ kubectl create secret generic secret-file --from-file=private-key=secret.txt

In this case, the key will be [.inline-code]private-key[.inline-code] instead of [.inline-code]secret.txt[.inline-code]

 $ kubectl get secret secret-file -o yaml
apiVersion: v1
data:
  private-key: U2VjcmV0IHRleHQgZmlsZQo=
kind: Secret
metadata:
  creationTimestamp: "2023-08-24T15:07:23Z"
  name: secret-file
  namespace: default
  resourceVersion: "1543"
  uid: b602f00b-dbeb-492c-8eb4-52608a1bd89f
type: Opaque

Note that you can use both the [.inline-code]--from-literal[.inline-code] and [.inline-code]--from-file[.inline-code] flags at the same time.

[#creating-a-docker-secret]Creating a Docker Secret[#creating-a-docker-secret]

Kubernetes Docker Secrets are a special kind of Secrets used by Kubernetes to authenticate with a Docker registry when pulling images for containers. This is common if you store your images in a private docker registry.

[#using-the-docker-configuration]Using the Docker configuration[#using-the-docker-configuration]

Docker usually stores your credentials or token information inside a file named [.inline-code]~/.docker/config.json[.inline-code] after logging in with the [.inline-code]docker login[.inline-code] command.

 $ cat ~/.docker/config.json
{
    "auths": {
        "my-registry.harbor.local": {
            "auth": "cm9ib3Q6QTlRYXlxYWxpTkVRTnAyM3NlS0tkUjg1MXFZckhHSHE="
        }
}

To create a Kubernetes Secret from this Docker configuration file, you can use the [.inline-code]kubectl create secret docker-registry[.inline-code] command as follows:

 $ cd ~
$ kubectl create secret docker-registry harbor-secret --from-file=.dockerconfigjson=.docker/config.json

Where the key will be set to [.inline-code].dockerconfigjson[.inline-code] and its value to the contents of the [.inline-code]~/.docker/config.json[.inline-code] file.

Note that unlike generic Secrets, this Docker Secret will have a [.inline-code]kubernetes.io/dockerconfigjson[.inline-code] type.

[#using-the-cli]Using the command-line interface[#using-the-cli]

Alternatively, you can directly create a Docker Secret in the command using the [.inline-code]--docker-server[.inline-code], [.inline-code]--docker-username[.inline-code] and [.inline-code]--docker-password[.inline-code] flags like so:

 $ kubectl create secret docker-registry demo-docker \
--docker-server=my-registry.harbor.local \
--docker-username=robot \
--docker-password=A9QayqaliNEQNp23seKKdR851qYrHGHq

You can then attach it to any pod spec to tell Kubernetes to use this Secret for pulling that image as follows:

 imagePullSecrets:
- demo-docker 

[#refreshing-tokens]Refreshing pull Secrets[#refreshing-tokens]

Note that if you are using a private registry that uses a custom CLI to generate a temporary token - like AWS’s ECR for instance - you will need to put in place a mechanism for your cluster to refresh the token.

A popular way to do this is by creating a special read-only account to your registry, and then creating a Kubernetes Job to periodically recreate the secret in Kubernetes.

[#creating-a-tls-secret]Creating a TLS Secret[#creating-a-tls-secret]

TLS Secrets are used for storing TLS certificates and keys for things like securing an ingress with HTTPS.

[#creating-a-self-signed-certificate]Creating a self-signed certificate[#creating-a-self-signed-certificate]

TLS certificates and keys can either be acquired from a Certificate Authority or self-signed.

To create a self-signed certificate, you can run the following [.inline-code]openssl[.inline-code] command:

 $ openssl req -newkey rsa:2048 -nodes -keyout server.pem -x509 -days 365 -out 
server.crt

Following the prompt with really only “Common Name” being important and should be set to the domain you are trying to secure.

[#creating-tls-secrets]Creating a TLS Secret[#creating-tls-secrets]

Once your TLS certificate and key downloaded or generated, you can create a TLS Secret using the following [.inline-code]kubectl create secret tls[.inline-code] command:

 $ kubectl create secret tls demo-tls --cert=server.crt --key=server.pem

Which will contain two keys: [.inline-code]tls.crt[.inline-code] and [.inline-code]tls.key[.inline-code].

You can then add the following configuration to your Ingress spec to enable TLS:

 tls:
  - hosts:
      - yourdomain.com
    secretName: demo-tls

You can learn more about certificates by reading our article on how to generate your own certificate signing request.

[#creating-a-secret-from-an-env-file]Creating a Secret from an env file [#creating-a-secret-from-an-env-file]

Env files are pretty popular in development with libraries like [.inline-code]dotenv[.inline-code] that allow you to load environment variables dynamically per program. Kubernetes allows you to create a regular generic secret from this type of file automatically.

For example, if we create a new env file called [.inline-code]staging.env[.inline-code]

 $ echo 'REDIS_HOST=redis-main' > staging.env
$ echo 'REDIS_PORT=8783' >> staging.env
$ cat staging.env
REDIS_HOST=redis-main
REDIS_PORT=8783

We can convert this file into a secret using the following command:

 $ kubectl create secret generic demo-env --from-env-file=staging.env
secret/demo-env created

$ kubectl get secret demo-env -o yaml
apiVersion: v1
data:
  REDIS_HOST: cmVkaXMtbWFpbg==
  REDIS_PORT: ODc4Mw==
kind: Secret
metadata:
  creationTimestamp: "2023-08-24T18:57:39Z"
  name: demo-env
  namespace: default
  resourceVersion: "4026"
  uid: 226f9f0d-9a22-40d6-84bf-68a1677a3492
type: Opaque

[#connecting-a-secret-to-a-pod]Connecting a Secret to a Pod[#connecting-a-secret-to-a-pod]

There are essentially two ways to attach a secret’s values to a pod:

  1. As a file mounted in a container.
  2. As an environment variable.

[#mounting-a-secret-as-a-file]Mounting a Secret as a file[#mounting-a-secret-as-a-file]

To mount a file into the container with the value of one of the secret’s keys, you can create a Pod file as follows:

 apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: my-image
    volumeMounts:
    - name: secret-volume
      mountPath: /etc/config
   volumes:
   - name: secret-volume
     secret:
       secretName: demo-env
       items:
       - key: REDIS_HOST
         path: redis_host.txt

There are two main parts here, the [.inline-code]volumes[.inline-code] key defines a new volume named [.inline-code]secret-volume[.inline-code]. The volume’s source is defined to be from a secret named [.inline-code]demo-secret[.inline-code] and we are saying take the key called [.inline-code]REDIS_HOST[.inline-code] from the secret and mount it as a file called ‘redis_host.txt’

The section above starting with [.inline-code]volumeMounts[.inline-code] takes the volume we defined and says to mount it at [.inline-code]/etc/config[.inline-code] so, in the end, we will have a file containing the value of REDIS_HOST mounted at [.inline-code]/etc/config/redis_host.txt[.inline-code]

[#mounting-a-secret-as-an-environment-variable]Mounting a Secret as an environment variable[#mounting-a-secret-as-an-environment-variable]

Attaching a secret to a container as an environment variable can be achieved using a [.inline-code]secretKeyRef[.inline-code] to reference a value from a secret when setting an environment variable.

For example, if we wanted to mount the [.inline-code]REDIS_HOST[.inline-code] key from our secret as an environment variable we can create the following pod file:

 apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: my-image
    env:
    - name: REDIS_HOST
      valueFrom:
        secretKeyRef:
          name: demo-env
          key: REDIS_HOST

Where:

  • [.inline-code]env.name[.inline-code] is how to call the environment variable inside the container.
  • [.inline-code]secretKeyRef.name[.inline-code] is the name of the secret.
  • [.inline-code]secretKeyRef.key[.inline-code] is the key inside the referenced secret we will attach to this environment variable.