Access Kubernetes Secret from 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.
And you should see also the same secret inside the 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.