Bootstrap FreeKB - Hashicorp Vault - Get secret in an OpenShift pod
Hashicorp Vault - Get secret in an OpenShift pod

Updated:   |  Hashicorp Vault articles

Let's say you have an application running on OpenShift and you want to fetch secrets from Hashicorp Vault. You will need to know the name of your Hashicorp Vault Kubernetes (k8s) auth role.

You will also need to know the relative path to where your secrets are mounted in Hashicorp Vault. For example, let's say the Hashicorp Vault secrets engine has been enabled with -path=secret/

~]# vault secrets enable -path=secret/ kv
Success! Enabled the kv secrets engine at: secret/

 

And let's say Kubernetes k8s role has been enabled and there is a role named "my-k8s-role" and contains a policy named "my-policy".

~]$ vault read auth/k8s/role/my-k8s-role
Key                        Value
---                        -----
policies                   [my-policy]

 

In this example, since the secrets engine has been enabled with -path=secret/ the policy path will need to begin with secret/. Let's say "my-policy" permits the following capabilities to "secret/my_path/*".

~]$ vault policy read my-policy
path "secret/my_path/*" {
  capabilities = ["create", "delete", "list", "patch", "read", "update"]
}

 

Assuming you are using a deployment.yaml for the creation of pods, you will add the following annotations. In this example, the name of the Hashicorp Vault Kubernetes (k8s) auth role is my-k8s-role.

spec:
  template:
    metadata:
      annotations:
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/role: my-k8s-role
        vault.hashicorp.com/agent-inject-secret-my-secret: my_path/my_secret

 

This should create a vault-agent-init container that, as the name suggests, initializes Hashicorp Vault.

]$ oc logs pod/my-pod-5c74857584-cctgc --container vault-agent-init
==> Vault Agent started! Log data will stream in below:
==> Vault Agent configuration:
           Api Address 1: http://bufconn
                     Cgo: disabled
               Log Level: info
                 Version: Vault v1.17.1, built 2024-06-25T16:33:25Z
             Version Sha: b8ab595639e7473eb153571521bbaf522cdafb27
2025-08-13T10:16:58.657Z [INFO]  agent.sink.file: creating file sink
2025-08-13T10:16:58.657Z [INFO]  agent.sink.file: file sink configured: path=/home/vault/.vault-token mode=-rw-r----- owner=1001990000 group=0
2025-08-13T10:16:58.657Z [INFO]  agent.exec.server: starting exec server
2025-08-13T10:16:58.657Z [INFO]  agent.exec.server: no env templates or exec config, exiting
2025-08-13T10:16:58.657Z [INFO]  agent.auth.handler: starting auth handler
2025-08-13T10:16:58.657Z [INFO]  agent.sink.server: starting sink server
2025-08-13T10:16:58.657Z [INFO]  agent.auth.handler: authenticating
2025-08-13T10:16:58.657Z [INFO]  agent.template.server: starting template server
2025-08-13T10:16:58.657Z [INFO]  agent: (runner) creating new runner (dry: false, once: false)
2025-08-13T10:16:58.657Z [INFO]  agent: (runner) creating watcher
2025-08-13T10:16:58.796Z [INFO]  agent.auth.handler: authentication successful, sending token to sinks
2025-08-13T10:16:58.796Z [INFO]  agent.auth.handler: starting renewal process
2025-08-13T10:16:58.797Z [INFO]  agent.template.server: template server received new token
2025-08-13T10:16:58.797Z [INFO]  agent: (runner) stopping
2025-08-13T10:16:58.797Z [INFO]  agent: (runner) creating new runner (dry: false, once: false)
2025-08-13T10:16:58.797Z [INFO]  agent.sink.file: token written: path=/home/vault/.vault-token
2025-08-13T10:16:58.797Z [INFO]  agent.sink.server: sink server stopped
2025-08-13T10:16:58.797Z [INFO]  agent: sinks finished, exiting
2025-08-13T10:16:58.797Z [INFO]  agent: (runner) creating watcher
2025-08-13T10:16:58.797Z [INFO]  agent: (runner) starting
2025-08-13T10:16:58.822Z [INFO]  agent.auth.handler: renewed auth token
2025-08-13T10:16:58.894Z [INFO]  agent: (runner) rendered "(dynamic)" => "/vault/secrets/poc"
2025-08-13T10:16:58.894Z [INFO]  agent: (runner) stopping
2025-08-13T10:16:58.894Z [INFO]  agent.template.server: template server stopped
2025-08-13T10:16:58.894Z [INFO]  agent: (runner) received finish
2025-08-13T10:16:58.894Z [INFO]  agent.auth.handler: shutdown triggered, stopping lifetime watcher
2025-08-13T10:16:58.894Z [INFO]  agent.auth.handler: auth handler stopped
2025-08-13T10:16:58.894Z [INFO]  agent.exec.server: exec server stopped

 

This should cause a vault-agent-init container to start up before your pods main container starts up, and if there are no issues, the vault-agent-init container should create a mount in your main container at /vault/secrets that contains a file matching the whatever you entered for vault.hashicorp.com/agent-inject-secret- (my-secret in this example).

~]$ oc exec pod/my-pod-5c74857584-cctgc --container my-main-container -- ls -l /vault/secrets
-rw-r--r--. 1 1001990000 1001990000 592 Aug 13 10:38 my-secret

 

This is kind of interesting because the content of the file (my-secret in this example) will contain something like this. In this example, my-secrets contains a map (aka an array or a list) that contains the keys and values in the secret.

~]$ oc exec pod/my-pod-5c74857584-cctgc --container my-main-container -- cat /vault/secrets/my-secret
data: map[foo:hello bar:world]
metadata: map[created_time:2025-05-14T10:00:30.818386645Z custom_metadata:<nil> deletion_time: destroyed:false version:16]

 

Let's say your pod only needs the vault of a single secret. In this scenario, you can include vault.hashicorp.com/agent-inject-template so that the file mounted in the container at /vault/secrets/my-secret contains the value of the specific key in the secret.

spec:
  template:
    metadata:
      annotations:
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/role: my-k8s-role
        vault.hashicorp.com/agent-inject-secret-my-secrets: my_path
        vault.hashicorp.com/agent-inject-status: "update"
        vault.hashicorp.com/agent-inject-template-my-secret: |
          {{- with secret "my_path/my-secret" -}}
            {{ .Data.data.foo}}
          {{- end }}

 

Now, instead of /vault/secrets/my-secret containing a data and metadata map, now /vault/secrets/my-secret will contain the value of the foo key in my-secret.

~]$ oc exec pod/my-pod-5c74857584-cctgc --container my-main-container -- cat /vault/secrets/my-secret
hello

 

Then you could do something like this in your app running in the container in the pod. For example, if your app is a Python app, you can fetch the value of the secret from the /vault/secrets/my-secret file in the container by reading the file.

file = open("/vault/secrets/my-secret", "r")
value = file.read()
file.close()

 

Let's say your pod only needs two or more keys in a secret. In this scenario, you'll almost always want to loop through each key/value pair in the secret.

spec:
  template:
    metadata:
      annotations:
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/role: my-k8s-role
        vault.hashicorp.com/agent-inject-secret-my-secrets: my_path
        vault.hashicorp.com/agent-inject-status: "update"
        vault.hashicorp.com/agent-inject-template-my-secret: |
          {{- with secret "my_path/my-secret" -}}
            {{ range $k, $v := .Data.data }}{{ $k }}={{ $v }} {{ end }}
          {{- end }}

 

Then you could do something like this in your app running in the container in the pod. For example, if your app is a Python app, you can fetch the value of the secret from the /vault/secrets/my-secret file in the container by reading the file.

file = open("/vault/secrets/my-secret", "r")
for line in file.read().split():
  if re.match(f"^foo:.*", line):
    value = line.split(':')[1]
file.close()  

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter 07a42c in the box below so that we can be sure you are a human.