Access Kubernetes Secret from Pod container

By Rex Resurreccion Aug 08, 2023
Access Kubernetes Secret in a Pod container

How to access Kubernetes secret from pod container? How to assign service account to a Pod?

On my previous tutorials, we have Deployed containerized application in Kubernetes. Also, we have set up a Cluster Role to manage Secrets. And bind a Service Account to a Cluster Role. This time, we will assign the Service Account to our Pod to have access to secrets through API.

Assign Service Account to Pod Deployment

Assuming you have already your Cluster Role for accessing the Secrets and Service Account. If you don’t have these set up yet, please follow the steps here.

Update the deployment for our example application webapp-example, adding the serviceAccountName configuration and the name of the Service account assigned to the Cluster Role that has permission to “get”, “create”, “patch” and “delete” a secret. In addition to that, we will create an environment variable USER_SECRETS with a value coming from a secret.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp-testing-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app.rex/name: webapp-example
  template:
    metadata:
      labels:
        app.rex/name: webapp-example
    spec:
      containers:
        - name: webapp-example-node
          image: rexresurreccionhome/webapp-for-testing:latest
          imagePullPolicy: Always
          env:
            - name: USER_SECRETS
              valueFrom:
                secretKeyRef:
                  name: webapp.some.random.unique.identifier
                  key: userSecrets
      serviceAccountName: webapp-service-account

Save the configuration file as k8s-deployment.yaml

How to create a Kubernetes Secret

We can create our secrets outside of our application. This is helpful when you have sensitive data like a password or secret key that you want to manage separately from your application. There are different types of secrets in Kubernetes. In this example, we are going to create an Opaque secret for arbitrary user-defined data. Notice the name of the secret webapp.some.random.unique.identifier is also the name specified in secretKeyRef in our deployment. This will allow us to load our secret data into an environment variable. And the data object contains a user defined key userSecrets with a base64 encoded value.

apiVersion: v1
kind: Secret
type: Opaque
metadata:
  namespace: default
  name: "webapp.some.random.unique.identifier"
  uid: cfee02d6-c137-11e5-8d73-42010af00002
  resourceVersion: "1"
  creationTimestamp: 2022-06-19T07:20:50.52Z
  labels:
    webapp.client/ID: "1234"
    webapp.client/Name: "Rex_R" 
data:
  userSecrets: eyJ1c2VybmFtZSI6ICJoZWxsb3dvcmxkIiwgInBhc3N3b3JkIjogIjEyMzQifQo=

Save the configuration file as k8s-secret.yaml

Now let’s deploy our new configurations

kubectl apply -f k8s-secret.yaml
kubectl apply -f k8s-deployment.yaml

Now if you go to your Kubernetes dashboard, you should be able to see the new Secret we’ve just deployed under Config and Storage.

Kubernetes Seceret

And you should see also the same secret inside the Pod environment variable.

Kubernetes Pod Environment Variable

Access Kubernetes Secret programmatically

Using environment variable to access secret is not always the most convenient way. Because this will also require to redeploy your application every time you have a new secret or when the value has changed. Another way to manage secrets directly is through API. Earlier in our deployment, we’ve already assigned the Service Account to our Pod serviceAccountName: webapp-service-account. This attaches the permission to send API actions like “get”, “create”, “patch” and “delete” secrets.

Below is an example Python code using the Kubernetes client library. Check out also the other supported client libraries.

import kubernetes
import base64
kubernetes.config.load_incluster_config()
k8s_api = kubernetes.client.CoreV1Api()
secret = k8s_api.read_namespaced_secret("webapp.some.random.unique.identifier", "default")
secret.data
# example output
# {'userSecrets': 'eyJ1c2VybmFtZSI6ICJoZWxsb3dvcmxkIiwgInBhc3N3b3JkIjogIjEyMzQifQo='}
base64.b64decode(secret.data.get("userSecrets")).decode("utf-8")
# '{"username": "helloworld", "password": "1234"}'
new_secret = kubernetes.client.V1Secret(
    kind="Secret",
    type="Opaque",
    metadata=kubernetes.client.V1ObjectMeta(
        name="webapp.clientSecret"
    ),
    string_data={"value":"Hello1234"},
    # example manually base64 encoding your data
    # data={"value":base64.b64encode(b"Hello1234").decode()},
)
k8s_api.create_namespaced_secret("default", new_secret )
# example update a secret
# k8s_api.patch_namespaced_secret(name="webapp.clientSecret", body=new_secret, namespace="default")
# example delete a secret
# k8s_api.delete_namespaced_secret("webapp.clientSecret", "default")

Summary

We’ve learned to attach a Service Account to a Pod. We also discussed different options we can access Kubernetes Secret from a Pod container through an environment variable and programmatically using the Client libraries.

© YippeeCode.com 2020