Providing sensitive data to pods by using secrets

Some applications need sensitive information, such as passwords and user names, that you do not want developers to have.

As an administrator, you can use Secret objects to provide this information without exposing that information in clear text.

Understanding secrets

The Secret object type provides a mechanism to hold sensitive information such as passwords, OKD client configuration files, private source repository credentials, and so on. Secrets decouple sensitive content from the pods. You can mount secrets into containers using a volume plugin or the system can use secrets to perform actions on behalf of a pod.

Key properties include:

  • Secret data can be referenced independently from its definition.

  • Secret data volumes are backed by temporary file-storage facilities (tmpfs) and never come to rest on a node.

  • Secret data can be shared within a namespace.

YAML Secret object definition

  1. apiVersion: v1
  2. kind: Secret
  3. metadata:
  4. name: test-secret
  5. namespace: my-namespace
  6. type: Opaque (1)
  7. data: (2)
  8. username: <username> (3)
  9. password: <password>
  10. stringData: (4)
  11. hostname: myapp.mydomain.com (5)
1Indicates the structure of the secret’s key names and values.
2The allowable format for the keys in the data field must meet the guidelines in the DNS_SUBDOMAIN value in the Kubernetes identifiers glossary.
3The value associated with keys in the data map must be base64 encoded.
4Entries in the stringData map are converted to base64 and the entry will then be moved to the data map automatically. This field is write-only; the value will only be returned via the data field.
5The value associated with keys in the stringData map is made up of plain text strings.

You must create a secret before creating the pods that depend on that secret.

When creating secrets:

  • Create a secret object with secret data.

  • Update the pod’s service account to allow the reference to the secret.

  • Create a pod, which consumes the secret as an environment variable or as a file (using a secret volume).

Types of secrets

The value in the type field indicates the structure of the secret’s key names and values. The type can be used to enforce the presence of user names and keys in the secret object. If you do not want validation, use the opaque type, which is the default.

Specify one of the following types to trigger minimal server-side validation to ensure the presence of specific key names in the secret data:

  • kubernetes.io/service-account-token. Uses a service account token.

  • kubernetes.io/basic-auth. Use with Basic Authentication.

  • kubernetes.io/ssh-auth. Use with SSH Key Authentication.

  • kubernetes.io/tls. Use with TLS certificate authorities.

Specify type: Opaque if you do not want validation, which means the secret does not claim to conform to any convention for key names or values. An opaque secret, allows for unstructured key:value pairs that can contain arbitrary values.

You can specify other arbitrary types, such as example.com/my-secret-type. These types are not enforced server-side, but indicate that the creator of the secret intended to conform to the key/value requirements of that type.

For examples of different secret types, see the code samples in Using Secrets.

Secret data keys

Secret keys must be in a DNS subdomain.

About automatically generated service account token secrets

When a service account is created, a service account token secret is automatically generated for it. This service account token secret, along with an automatically generated docker configuration secret, is used to authenticate to the internal OKD registry. Do not rely on these automatically generated secrets for your own use; they might be removed in a future OKD release.

Prior to OKD 4.11, a second service account token secret was generated when a service account was created. This service account token secret was used to access the Kubernetes API.

Starting with OKD 4.11, this second service account token secret is no longer created. This is because the LegacyServiceAccountTokenNoAutoGeneration upstream Kubernetes feature gate was enabled, which stops the automatic generation of secret-based service account tokens to access the Kubernetes API.

After upgrading to 4, any existing service account token secrets are not deleted and continue to function.

Workloads are automatically injected with a projected volume to obtain a bound service account token. If your workload needs an additional service account token, add an additional projected volume in your workload manifest. Bound service account tokens are more secure than service account token secrets for the following reasons:

  • Bound service account tokens have a bounded lifetime.

  • Bound service account tokens contain audiences.

  • Bound service account tokens can be bound to pods or secrets and the bound tokens are invalidated when the bound object is removed.

For more information, see Configuring bound service account tokens using volume projection.

You can also manually create a service account token secret to obtain a token, if the security exposure of a non-expiring token in a readable API object is acceptable to you. For more information, see Creating a service account token secret.

Additional resources

Understanding how to create secrets

As an administrator you must create a secret before developers can create the pods that depend on that secret.

When creating secrets:

  1. Create a secret object that contains the data you want to keep secret. The specific data required for each secret type is descibed in the following sections.

    Example YAML object that creates an opaque secret

    1. apiVersion: v1
    2. kind: Secret
    3. metadata:
    4. name: test-secret
    5. type: Opaque (1)
    6. data: (2)
    7. username: <username>
    8. password: <password>
    9. stringData: (3)
    10. hostname: myapp.mydomain.com
    11. secret.properties: |
    12. property1=valueA
    13. property2=valueB
    1Specifies the type of secret.
    2Specifies encoded string and data.
    3Specifies decoded string and data.

    Use either the data or stringdata fields, not both.

  2. Update the pod’s service account to reference the secret:

    YAML of a service account that uses a secret

    1. apiVersion: v1
    2. kind: ServiceAccount
    3. ...
    4. secrets:
    5. - name: test-secret
  3. Create a pod, which consumes the secret as an environment variable or as a file (using a secret volume):

    YAML of a pod populating files in a volume with secret data

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: secret-example-pod
    5. spec:
    6. containers:
    7. - name: secret-test-container
    8. image: busybox
    9. command: [ "/bin/sh", "-c", "cat /etc/secret-volume/*" ]
    10. volumeMounts: (1)
    11. - name: secret-volume
    12. mountPath: /etc/secret-volume (2)
    13. readOnly: true (3)
    14. volumes:
    15. - name: secret-volume
    16. secret:
    17. secretName: test-secret (4)
    18. restartPolicy: Never
    1Add a volumeMounts field to each container that needs the secret.
    2Specifies an unused directory name where you would like the secret to appear. Each key in the secret data map becomes the filename under mountPath.
    3Set to true. If true, this instructs the driver to provide a read-only volume.
    4Specifies the name of the secret.

    YAML of a pod populating environment variables with secret data

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: secret-example-pod
    5. spec:
    6. containers:
    7. - name: secret-test-container
    8. image: busybox
    9. command: [ "/bin/sh", "-c", "export" ]
    10. env:
    11. - name: TEST_SECRET_USERNAME_ENV_VAR
    12. valueFrom:
    13. secretKeyRef: (1)
    14. name: test-secret
    15. key: username
    16. restartPolicy: Never
    1Specifies the environment variable that consumes the secret key.

    YAML of a build config populating environment variables with secret data

    1. apiVersion: build.openshift.io/v1
    2. kind: BuildConfig
    3. metadata:
    4. name: secret-example-bc
    5. spec:
    6. strategy:
    7. sourceStrategy:
    8. env:
    9. - name: TEST_SECRET_USERNAME_ENV_VAR
    10. valueFrom:
    11. secretKeyRef: (1)
    12. name: test-secret
    13. key: username
    14. from:
    15. kind: ImageStreamTag
    16. namespace: openshift
    17. name: 'cli:latest'
    1Specifies the environment variable that consumes the secret key.

Secret creation restrictions

To use a secret, a pod needs to reference the secret. A secret can be used with a pod in three ways:

  • To populate environment variables for containers.

  • As files in a volume mounted on one or more of its containers.

  • By kubelet when pulling images for the pod.

Volume type secrets write data into the container as a file using the volume mechanism. Image pull secrets use service accounts for the automatic injection of the secret into all pods in a namespace.

When a template contains a secret definition, the only way for the template to use the provided secret is to ensure that the secret volume sources are validated and that the specified object reference actually points to a Secret object. Therefore, a secret needs to be created before any pods that depend on it. The most effective way to ensure this is to have it get injected automatically through the use of a service account.

Secret API objects reside in a namespace. They can only be referenced by pods in that same namespace.

Individual secrets are limited to 1MB in size. This is to discourage the creation of large secrets that could exhaust apiserver and kubelet memory. However, creation of a number of smaller secrets could also exhaust memory.

Creating an opaque secret

As an administrator, you can create an opaque secret, which allows you to store unstructured key:value pairs that can contain arbitrary values.

Procedure

  1. Create a Secret object in a YAML file on a control plane node.

    For example:

    1. apiVersion: v1
    2. kind: Secret
    3. metadata:
    4. name: mysecret
    5. type: Opaque (1)
    6. data:
    7. username: <username>
    8. password: <password>
    1Specifies an opaque secret.
  2. Use the following command to create a Secret object:

    1. $ oc create -f <filename>.yaml
  3. To use the secret in a pod:

    1. Update the pod’s service account to reference the secret, as shown in the “Understanding how to create secrets” section.

    2. Create the pod, which consumes the secret as an environment variable or as a file (using a secret volume), as shown in the “Understanding how to create secrets” section.

Additional resources

Creating a service account token secret

As an administrator, you can create a service account token secret, which allows you to distribute a service account token to applications that must authenticate to the API.

It is recommended to obtain bound service account tokens using the TokenRequest API instead of using service account token secrets. The tokens obtained from the TokenRequest API are more secure than the tokens stored in secrets, because they have a bounded lifetime and are not readable by other API clients.

You should create a service account token secret only if you cannot use the TokenRequest API and if the security exposure of a non-expiring token in a readable API object is acceptable to you.

See the Additional resources section that follows for information on creating bound service account tokens.

Procedure

  1. Create a Secret object in a YAML file on a control plane node:

    Example secret object:

    1. apiVersion: v1
    2. kind: Secret
    3. metadata:
    4. name: secret-sa-sample
    5. annotations:
    6. kubernetes.io/service-account.name: "sa-name" (1)
    7. type: kubernetes.io/service-account-token (2)
    1Specifies an existing service account name. If you are creating both the ServiceAccount and the Secret objects, create the ServiceAccount object first.
    2Specifies a service account token secret.
  2. Use the following command to create the Secret object:

    1. $ oc create -f <filename>.yaml
  3. To use the secret in a pod:

    1. Update the pod’s service account to reference the secret, as shown in the “Understanding how to create secrets” section.

    2. Create the pod, which consumes the secret as an environment variable or as a file (using a secret volume), as shown in the “Understanding how to create secrets” section.

Additional resources

Creating a basic authentication secret

As an administrator, you can create a basic authentication secret, which allows you to store the credentials needed for basic authentication. When using this secret type, the data parameter of the Secret object must contain the following keys encoded in the base64 format:

  • username: the user name for authentication

  • password: the password or token for authentication

You can use the stringData parameter to use clear text content.

Procedure

  1. Create a Secret object in a YAML file on a control plane node:

    Example secret object

    1. apiVersion: v1
    2. kind: Secret
    3. metadata:
    4. name: secret-basic-auth
    5. type: kubernetes.io/basic-auth (1)
    6. data:
    7. stringData: (2)
    8. username: admin
    9. password: <password>
    1Specifies a basic authentication secret.
    2Specifies the basic authentication values to use.
  2. Use the following command to create the Secret object:

    1. $ oc create -f <filename>.yaml
  3. To use the secret in a pod:

    1. Update the pod’s service account to reference the secret, as shown in the “Understanding how to create secrets” section.

    2. Create the pod, which consumes the secret as an environment variable or as a file (using a secret volume), as shown in the “Understanding how to create secrets” section.

Additional resources

Creating an SSH authentication secret

As an administrator, you can create an SSH authentication secret, which allows you to store data used for SSH authentication. When using this secret type, the data parameter of the Secret object must contain the SSH credential to use.

Procedure

  1. Create a Secret object in a YAML file on a control plane node:

    Example secret object:

    1. apiVersion: v1
    2. kind: Secret
    3. metadata:
    4. name: secret-ssh-auth
    5. type: kubernetes.io/ssh-auth (1)
    6. data:
    7. ssh-privatekey: | (2)
    8. MIIEpQIBAAKCAQEAulqb/Y ...
    1Specifies an SSH authentication secret.
    2Specifies the SSH key/value pair as the SSH credentials to use.
  2. Use the following command to create the Secret object:

    1. $ oc create -f <filename>.yaml
  3. To use the secret in a pod:

    1. Update the pod’s service account to reference the secret, as shown in the “Understanding how to create secrets” section.

    2. Create the pod, which consumes the secret as an environment variable or as a file (using a secret volume), as shown in the “Understanding how to create secrets” section.

Additional resources

Creating a Docker configuration secret

As an administrator, you can create a Docker configuration secret, which allows you to store the credentials for accessing a container image registry.

  • kubernetes.io/dockercfg. Use this secret type to store your local Docker configuration file. The data parameter of the secret object must contain the contents of a .dockercfg file encoded in the base64 format.

  • kubernetes.io/dockerconfigjson. Use this secret type to store your local Docker configuration JSON file. The data parameter of the secret object must contain the contents of a .docker/config.json file encoded in the base64 format.

Procedure

  1. Create a Secret object in a YAML file on a control plane node.

    Example Docker configuration secret object

    1. apiVersion: v1
    2. kind: Secret
    3. metadata:
    4. name: secret-docker-cfg
    5. namespace: my-project
    6. type: kubernetes.io/dockerconfig (1)
    7. data:
    8. .dockerconfig:bm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg== (2)
    1Specifies that the secret is using a Docker configuration file.
    2The output of a base64-encoded Docker configuration file

    Example Docker configuration JSON secret object

    1. apiVersion: v1
    2. kind: Secret
    3. metadata:
    4. name: secret-docker-json
    5. namespace: my-project
    6. type: kubernetes.io/dockerconfig (1)
    7. data:
    8. .dockerconfigjson:bm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg== (2)
    1Specifies that the secret is using a Docker configuration JSONfile.
    2The output of a base64-encoded Docker configuration JSON file
  2. Use the following command to create the Secret object

    1. $ oc create -f <filename>.yaml
  3. To use the secret in a pod:

    1. Update the pod’s service account to reference the secret, as shown in the “Understanding how to create secrets” section.

    2. Create the pod, which consumes the secret as an environment variable or as a file (using a secret volume), as shown in the “Understanding how to create secrets” section.

Additional resources

Creating a secret using the web console

You can create secrets using the web console.

Procedure

  1. Navigate to WorkloadsSecrets.

  2. Click CreateFrom YAML.

    1. Edit the YAML manually to your specifications, or drag and drop a file into the YAML editor. For example:

      1. apiVersion: v1
      2. kind: Secret
      3. metadata:
      4. name: example
      5. namespace: <namespace>
      6. type: Opaque (1)
      7. data:
      8. username: <base64 encoded username>
      9. password: <base64 encoded password>
      10. stringData: (2)
      11. hostname: myapp.mydomain.com
      1This example specifies an opaque secret; however, you may see other secret types such as service account token secret, basic authentication secret, SSH authentication secret, or a secret that uses Docker configuration.
      2Entries in the stringData map are converted to base64 and the entry will then be moved to the data map automatically. This field is write-only; the value will only be returned via the data field.
  3. Click Create.

  4. Click Add Secret to workload.

    1. From the drop-down menu, select the workload to add.

    2. Click Save.

Understanding how to update secrets

When you modify the value of a secret, the value (used by an already running pod) will not dynamically change. To change a secret, you must delete the original pod and create a new pod (perhaps with an identical PodSpec).

Updating a secret follows the same workflow as deploying a new Container image. You can use the kubectl rolling-update command.

The resourceVersion value in a secret is not specified when it is referenced. Therefore, if a secret is updated at the same time as pods are starting, the version of the secret that is used for the pod is not defined.

Currently, it is not possible to check the resource version of a secret object that was used when a pod was created. It is planned that pods will report this information, so that a controller could restart ones using an old resourceVersion. In the interim, do not update the data of existing secrets, but create new ones with distinct names.

Creating and using secrets

As an administrator, you can create a service account token secret. This allows you to distribute a service account token to applications that must authenticate to the API.

Procedure

  1. Create a service account in your namespace by running the following command:

    1. $ oc create sa <service_account_name> -n <your_namespace>
  2. Save the following YAML example to a file named service-account-token-secret.yaml. The example includes a Secret object configuration that you can use to generate a service account token:

    1. apiVersion: v1
    2. kind: Secret
    3. metadata:
    4. name: <secret_name> (1)
    5. annotations:
    6. kubernetes.io/service-account.name: "sa-name" (2)
    7. type: kubernetes.io/service-account-token (3)
    1Replace <secret_name> with the name of your service token secret.
    2Specifies an existing service account name. If you are creating both the ServiceAccount and the Secret objects, create the ServiceAccount object first.
    3Specifies a service account token secret type.
  3. Generate the service account token by applying the file:

    1. $ oc apply -f service-account-token-secret.yaml
  4. Get the service account token from the secret by running the following command:

    1. $ oc get secret <sa_token_secret> -o jsonpath='{.data.token}' | base64 --decode (1)

    Example output

    1. ayJhbGciOiJSUzI1NiIsImtpZCI6IklOb2dtck1qZ3hCSWpoNnh5YnZhSE9QMkk3YnRZMVZoclFfQTZfRFp1YlUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImJ1aWxkZXItdG9rZW4tdHZrbnIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiYnVpbGRlciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjNmZGU2MGZmLTA1NGYtNDkyZi04YzhjLTNlZjE0NDk3MmFmNyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmJ1aWxkZXIifQ.OmqFTDuMHC_lYvvEUrjr1x453hlEEHYcxS9VKSzmRkP1SiVZWPNPkTWlfNRp6bIUZD3U6aN3N7dMSN0eI5hu36xPgpKTdvuckKLTCnelMx6cxOdAbrcw1mCmOClNscwjS1KO1kzMtYnnq8rXHiMJELsNlhnRyyIXRTtNBsy4t64T3283s3SLsancyx0gy0ujx-Ch3uKAKdZi5iT-I8jnnQ-ds5THDs2h65RJhgglQEmSxpHrLGZFmyHAQI-_SjvmHZPXEc482x3SkaQHNLqpmrpJorNqh1M8ZHKzlujhZgVooMvJmWPXTb2vnvi3DGn2XI-hZxl1yD2yGH1RBpYUHA
    1Replace <sa_token_secret> with the name of your service token secret.
  5. Use your service account token to authenticate with the API of your cluster:

    1. $ curl -X GET <openshift_cluster_api> --header "Authorization: Bearer <token>" (1) (2)
    1Replace <openshift_cluster_api> with the OpenShift cluster API.
    2Replace <token> with the service account token that is output in the preceding command.

About using signed certificates with secrets

To secure communication to your service, you can configure OKD to generate a signed serving certificate/key pair that you can add into a secret in a project.

A service serving certificate secret is intended to support complex middleware applications that need out-of-the-box certificates. It has the same settings as the server certificates generated by the administrator tooling for nodes and masters.

Service Pod spec configured for a service serving certificates secret.

  1. apiVersion: v1
  2. kind: Service
  3. metadata:
  4. name: registry
  5. annotations:
  6. service.beta.openshift.io/serving-cert-secret-name: registry-cert(1)
  7. # ...
1Specify the name for the certificate

Other pods can trust cluster-created certificates (which are only signed for internal DNS names), by using the CA bundle in the /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt file that is automatically mounted in their pod.

The signature algorithm for this feature is x509.SHA256WithRSA. To manually rotate, delete the generated secret. A new certificate is created.

Generating signed certificates for use with secrets

To use a signed serving certificate/key pair with a pod, create or edit the service to add the service.beta.openshift.io/serving-cert-secret-name annotation, then add the secret to the pod.

Procedure

To create a service serving certificate secret:

  1. Edit the Pod spec for your service.

  2. Add the service.beta.openshift.io/serving-cert-secret-name annotation with the name you want to use for your secret.

    1. kind: Service
    2. apiVersion: v1
    3. metadata:
    4. name: my-service
    5. annotations:
    6. service.beta.openshift.io/serving-cert-secret-name: my-cert (1)
    7. spec:
    8. selector:
    9. app: MyApp
    10. ports:
    11. - protocol: TCP
    12. port: 80
    13. targetPort: 9376

    The certificate and key are in PEM format, stored in tls.crt and tls.key respectively.

  3. Create the service:

    1. $ oc create -f <file-name>.yaml
  4. View the secret to make sure it was created:

    1. View a list of all secrets:

      1. $ oc get secrets

      Example output

      1. NAME TYPE DATA AGE
      2. my-cert kubernetes.io/tls 2 9m
    2. View details on your secret:

      1. $ oc describe secret my-cert

      Example output

      1. Name: my-cert
      2. Namespace: openshift-console
      3. Labels: <none>
      4. Annotations: service.beta.openshift.io/expiry: 2023-03-08T23:22:40Z
      5. service.beta.openshift.io/originating-service-name: my-service
      6. service.beta.openshift.io/originating-service-uid: 640f0ec3-afc2-4380-bf31-a8c784846a11
      7. service.beta.openshift.io/expiry: 2023-03-08T23:22:40Z
      8. Type: kubernetes.io/tls
      9. Data
      10. ====
      11. tls.key: 1679 bytes
      12. tls.crt: 2595 bytes
  5. Edit your Pod spec with that secret.

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: my-service-pod
    5. spec:
    6. containers:
    7. - name: mypod
    8. image: redis
    9. volumeMounts:
    10. - name: my-container
    11. mountPath: "/etc/my-path"
    12. volumes:
    13. - name: my-volume
    14. secret:
    15. secretName: my-cert
    16. items:
    17. - key: username
    18. path: my-group/my-username
    19. mode: 511

    When it is available, your pod will run. The certificate will be good for the internal service DNS name, <service.name>.<service.namespace>.svc.

    The certificate/key pair is automatically replaced when it gets close to expiration. View the expiration date in the service.beta.openshift.io/expiry annotation on the secret, which is in RFC3339 format.

    In most cases, the service DNS name <service.name>.<service.namespace>.svc is not externally routable. The primary use of <service.name>.<service.namespace>.svc is for intracluster or intraservice communication, and with re-encrypt routes.

Troubleshooting secrets

If a service certificate generation fails with (service’s service.beta.openshift.io/serving-cert-generation-error annotation contains):

  1. secret/ssl-key references serviceUID 62ad25ca-d703-11e6-9d6f-0e9c0057b608, which does not match 77b6dd80-d716-11e6-9d6f-0e9c0057b60

The service that generated the certificate no longer exists, or has a different serviceUID. You must force certificates regeneration by removing the old secret, and clearing the following annotations on the service service.beta.openshift.io/serving-cert-generation-error, service.beta.openshift.io/serving-cert-generation-error-num:

  1. Delete the secret:

    1. $ oc delete secret <secret_name>
  2. Clear the annotations:

    1. $ oc annotate service <service_name> service.beta.openshift.io/serving-cert-generation-error-
    1. $ oc annotate service <service_name> service.beta.openshift.io/serving-cert-generation-error-num-

The command removing annotation has a - after the annotation name to be removed.