Secrets

Last modified by Tomas Terälä on 2025/03/21 13:49

This page is under construction. You will find info about Secrets CSI driver, SealedSecrets, External Secrets and other possible solutions here.

Types of Secrets

There are multiple types of Secrets, but this instruction set will focus on Opaque, or key-value pair Secrets. More info in Kubernetes docs.

Creating a Secret

There are 3 main ways of creating a Secret.

  1. Creating one from a yaml file, where each key: value pair is placed under stringData. If you wish to base64 encode the values for yourself, switch out stringData for data.
apiVersion: v1
kind: Secret
metadata:
 name: my-secret
 namespace: my-namespace
type: Opaque
stringData:
 key1: value1
 key2: value2

you can then use oc apply -f <filename> or add it from the +-symbol of the OpenShift UI.

  1. From the terminal with the command oc create secret
oc create secret generic my-secret --from-literal=key1=value1 --from-literal=key2=value2 -n my-namespace

More options and info in Kubernetes docs

  1. From the UI

Navigate to the Secrets page and then click Create and choose your type of secret. The UI will guide you through the rest.

  • Developer -> Secrets
  • Administrator -> Workloads -> Secrets

NOTE: Secrets are, as the name implies, to be kept secret. Do not put them in version control etc.

Checking the contents of a Secret

From the command line

You can retrieve the base64 encoded values for all keys with the oc get command, and then you can decode them by using echo and base64.

# get all values in base64
$ oc get secret mysecret -o jsonpath='{.data}'
{"key1":"dmFsdWUx","key2":"dmFsdWUy"}

# decode a single value
$ echo "dmFsdWUx" | base64 --decode
value1

# to check the keys in a secret without revealing them, use the oc describe command
# you can also check this from the yaml or by going to the OpenShift UI
$ oc describe secret mysecret
...
Data
====
database-user:           7 bytes
database-name:           8 bytes
database-password:       16 bytes
database-root-password:  16 bytes

The Kubernetes docs mention a way of inline decoding a single key’s value, but since it is not recommended we won’t list it here.

Retrieving a Secret

You can retrieve the Secret, either from the UI or from the command line. We recommend using the oc get command, since the UI will add a lot of unnecessary information (unless you only copy what is necessary).

Retrieving a Secret (cli)

You can retrieve a Secret, just like any Kubernetes object by using the oc get <kind> <name> -oyaml. You can also output it directly into a file by adding > filename.yaml at the end of the command. Remember that since the uid and creationTimeStamp are related to this specific object in this specific cluster, you should delete them.

# print the object into the terminal
oc get secret my-secret -n my-namespace -oyaml

apiVersion: v1
data:
  key1: dmFsdWUx
  key2: dmFsdWUy
kind: Secret
metadata:
  creationTimestamp: "2024-07-10T10:15:03Z"
  name: my-secret
  namespace: my-namespace
  resourceVersion: "1094313948"
  uid: 5c9b2418-49ab-4469-ae73-05a9ab978bf0
type: Opaque

# create a file called filename.yaml with the contents of the object
oc get secret my-secret -n my-namespace -oyaml > filename.yaml

Retrieving a Secret (UI)

From the UI

You can check out Secret objects from both the Developer and the Administrator perspectives, but the path changes slightly. You can either reveal all values, copy a single one from the UI without revealing it or show the yaml that defines the Secret.

  • Developer -> Secrets -> my-secret
  • Administrator -> Workloads -> Secrets -> my-secret

Revealing the values and copying a single value without revealing it happen from the Details tab of the Secret, and the yaml is found on the YAML tab. The OpenShift UI add a lot of information under metadata, but we only need the name, namespace and possible labels or annotations for it.

kind: Secret
apiVersion: v1
metadata:
 name: my-secret
 namespace: test-dummies
 uid: 5c9b2418-49ab-4469-ae73-05a9ab978bf0
 resourceVersion: '1094313948'
 creationTimestamp: '2024-07-10T10:15:03Z'
 managedFields:
    - manager: kubectl-create
     operation: Update
     apiVersion: v1
     time: '2024-07-10T10:15:03Z'
     fieldsType: FieldsV1
     fieldsV1:
       'f:data':
         .: {}
         'f:key1': {}
         'f:key2': {}
       'f:type': {}
data:
 key1: dmFsdWUx
 key2: dmFsdWUy
type: Opaque

Editing a Secret

You can either edit the Secret in the cluster with oc edit secret mysecret, edit a local copy and use oc apply -f <filename> or use Actions -> Edit Secret from the OpenShift UI.

SealedSecrets

Since SealedSecrets is already available in Tike Container platform, we will start with it. It consist of two parts, the operator running in the cluster that is provided by container administration, and a client side utility called kubeseal. The idea is to encrypt the contents of a Secret objects against a sealing key that is managed and automatically renewed by the operator in each cluster, so that the created SealedSecret object can be placed in version control.

By default, the Secret is encrypted with knowledge of the correct namespace, which means that the the encrypted definition can’t be reused as-is in another namespace. This is to help against other users of the same cluster getting access to your Secrets.

  • The kubeseal utility uses asymmetric crypto to encrypt secrets that only the controller can decrypt. Source

NOTE 1: Always download the most recent version of the kubeseal binary using the instructions on the Github page and notify container administration if there are issues related to version numbers between the kubeseal binary and the sealed-secrets operator running in the cluster.

NOTE 2: The sealed-secrets documentation mentions, that the sealing key is renewed every 30 days, but since encryption happens outside the cluster, old keys will not be deleted. This lessens the impact of a single sealing-key leaking, but is not equal to key rotation.

NOTE 3: As stated before, SealedSecrets are encrypted and therefore can be set in version control, unlike Secrets.

Using Sealed Secrets

  1. Acquire a Secret, either by making one through the OpenShift UI or by using oc/kubectl commands. For instructions, check Creating a Secret from above. The Sealed Secrets Github page has more comprehensive instructions. If you copy the Secret from inside OpenShift, we recommend clearing the bits of metadata you don’t need, only leaving name, namespace and the necessary parts under labels or annotations. Remember that you need to use stringData for plaintext values and data for base64 encoded values, so that the Sealed Secret operator knows how to decrypt the Secret
    kind: Secret
    apiVersion: v1
    metadata:
     name: example-secret
     namespace: dokumentaatio
    data:
     password: cGxhY2Vob2xkZXI=
     username: cGxhY2Vob2xkZXI=
    type: Opaque
  2. Login to the correct cluster with oc. Make a local file and use the kubeseal command against it.
    kubeseal -f <filename> -w <file-output-name>
    e.g.
    kubeseal -f secret.yaml -w sealedsecret.yaml

This will create a file called sealedsecret.yaml that looks a little something like this. As you can see, the created SealedSecret has the same name as the Secret it was created from.

apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
 creationTimestamp: null
 name: example-secret
 namespace: dokumentaatio
spec:
 encryptedData:
   password: AgBybvH9eX3YiyY0QKbXGzqeqd4DIDnlyTr5ebl81VNYK6j5tnVmC8LSQxZUKvyhg5cId5b19EuDA+N54sUJeswghwWKITWJZ/sbDRxwB691xny86VjwxIBiTzXDt5CBn7XLWvXgzi5n2NZkb9yvI2nrCAWrW6Uvr+zy0xFzojy1d9KCqHkrjhVf+0so1PX5xCIpHfUzEcNjQeM14Qs35UDqquh0WbgvRgFfqTXhUq0Tn7mm2pO0CmS52qkQNY3Xyr2/gySFUg4UTFDWc4tUariJprhU81DuxzSGV65eh4NAqNFf6toZO3N/u+q1/UurDyX8xjk7gCMFzxpAYZm2WxqCc1aHdAPMSIAehF5oF/NZJOBx8DMA6MsUlISYRRyTzL5SlUPZW06tcycquxfB37SIWs5ussGGxS4nQ8OES16JfzV6GQiQikNy6f8d7xxZ7jQPoYKCpuSDfFxkC+QkIAmcLSJkU4KMBYta5v46zXAk5GWPR78qKJldepctiBiekfhgMVi82Y06ClqxXNY+ZvVjbzgX3fnhmj6gdTgb3+qMgeGZAyyN+yyu8jpW3q7QoBpRtbjFKtYsSgaJbwKavgtbAuw/QEhffPiLYH0/5g1eW3XROk/3cecbp0460KAcM74sDtzDFM21baf9qKtichKtUocw6bT0OYPZzHyd9Jg8EVwJyxq6bNwjxK7+8On6CSyYwojKs8vls2XZtg==
   username: AgCJ+f1f2bqR+Ho4rqfHnZ6E6tXWEyA7tc6bG22GmOh/3SJfUI/lOnAnqqlT7zjBl8uiIC0VJKKM1ho8oaHXwmdXdiAstwKAUqtUBYDEG1sQSpCe1DSHcIljlifdwMvKMyaY/Qr3208Py+TMRoyrWaCDKl8PGeuznKi0ClXcKdsvFzsZjZWZ0RbvKdBkmDw0Hs763wDeKF1IZQKY5GMHUUdOJnuIcj9zywbW/sgv0rEdvhmS0VF6UV0ArbXuglZ7Ocj2kYLEmdtzZBEfgb6LYi5WH6rBVtXhYP28M1VWanwmzDP5ttFylEni46h1nlkb+gJ/sWKnYSE6lQyFEPOC4+S69MKXigAhNFjXfqCimsVsE+HypOfksQsYTMGAUAaBbtOMsF51vXmMFeA8Lv+af5VqkftUnysqRcJl5oxzO4H5VP0a5NenqMpIFlkGROqFOciqYjQmhktIUeIkwZUfVRHRadl/zGiafu9pRktxh3PKbulPz/+gpWkRxG4DHgXpo1hg/wV0nzPrPVAUZHStGyl/5sqQYF/lg0uxHOKLJzAxNH7I8D5mB+w83gSCgjsaCjvF+flWeBqX32+MrvGcJGojTFfsjeZonnSJ1S91KmYLA7XNNKRsoJ3DjooWaAwCa583TPGQEvCwpZYrL5S3XhrSv/LkL0f/Rj7vZE0XcwtsDgR2crsDOA8maVAUgJffmM0lF660mN3OGlifoQ==
 template:
   metadata:
     creationTimestamp: null
     name: example-secret
     namespace: dokumentaatio
   type: Opaque
  1. Add the SealedSecret into your version control.
  2. (If no CI/CD process is in place, add the SealedSecret into OpenShift)

This can be done either with oc apply -f <filename> or by using the + symbol in the OpenShift UI.

  1. Check the status of the SealedSecret.
oc describe sealedsecret <name> -n <namespace>

or by using the Search feature of the UI. For us, since the Secret already exists in the cluster, we will get this output.

oc describe sealedsecret example-secret -n dokumentaatio
...
Events:
  Type     Reason           Age                From            Message
  ----     ------           ----               ----            -------
  Warning  ErrUpdateFailed  40s (x6 over 41s)  sealed-secrets  Resource "example-secret" already exists and is not managed by SealedSecret

The “Resource already exists and is not managed by SealedSecret” can be corrected by deleting the original Secret from the cluster. After a while the SealedSecret should report

Events:
  Type    Reason    Age   From            Message
  ----    ------    ----  ----            -------
  Normal  Unsealed  3s    sealed-secrets  SealedSecret unsealed successfully

You can also check that the new Secret should have an owner reference to the SealedSecret in it’s yaml.

metadata:
  ownerReferences:
  - apiVersion: bitnami.com/v1alpha1
    controller: true
    kind: SealedSecret
    name: example-secret
    uid: 50c3d0a9-1a93-4dfd-997e-e01ed9758f9c
  1. After confirming the SealedSecret works and that the contents of the Secret are correct, remember to delete the secret file from your computer.

Updating a SealedSecret

If you need to update the contents of a Secret managed by a SealedSecret, retrieve the Secret or create it manually and add the new/changed values. Retrieval instructions can be found here. Then re-run the steps from Using Sealed Secrets.

Known issues

No key could unseal

Since the Secret is encrypted against each cluster, you would need to create a separate SealedSecret for each cluster. If you run into the error “Failed to unseal: no key could decrypt secret (value1, value2..)”, you were logged in to the wrong cluster while using kubeseal or tried manually editing the namespace inside the SealedSecret object.

Events:
  Type     Reason           Age                From            Message
  ----     ------           ----               ----            -------
  Warning  ErrUnsealFailed  11s (x3 over 12s)  sealed-secrets  Failed to unseal: no key could decrypt secret (username, password)

Log in to the correct cluster, use the kubeseal command in part 2 again and then oc apply -f <filename>. The SealedSecret should be fine after this.

The Secret contents look wrong

This usually happens by manually creating the text definition of a Secret with plaintext values under data, and then using kubeseal on the file. Make sure to have the starting Secret in the correct form. More info in Creating a Secret.

I want my CI/CD solution to make SealedSecrets

Your CI/CD solution either needs a service account with permission to authenticate to the to the cluster, or you need to download the public key from the cluster. According to the Github docs, downloading the public key can be done with

kubeseal --fetch-cert >mycert.pem

and then can be used in the kubeseal command with the flag --cert

kubeseal --cert <certificate-file>

I want to change the name/namespace of the Secret

Just change the name of the Secret before using kubeseal, apply the new file and delete the old SealedSecret object.

I don’t have access to the cluster but need to decrypt a SealedSecret

Please ask the project owner to contact the container administration with the SealedSecret file and knowledge of the cluster the SealedSecret was created against. We can decrypt the Secret information, and will give it to the project owner.