Deploying applications that act as secret consumers of Vault require the application to:
- Authenticate and acquire a client token.
- Manage the lifecycle of the token.
- Retrieve secrets from Vault.
- Manage the leases of any dynamic secrets.
Vault Agent takes responsibility for these tasks and enables your applications to remain unaware of Vault. However, this introduces a new requirement that deployments install and configure Vault Agent alongside the application as a sidecar.
The Vault Helm chart enables you to run Vault and the Vault Agent Injector service. This injector service leverages the Kubernetes mutating admission webhook to intercept pods that define specific annotations and inject a Vault Agent container to manage these secrets. This is beneficial because:
- Applications remain Vault unaware as the secrets are stored on the file-system within their container.
- Existing deployments require no change; as annotations can be patched.
- Access to secrets can be enforced via Kubernetes service accounts and namespaces
In this tutorial, you setup Vault and this injector service with the Vault Helm chart. Then you will deploy several applications to demonstrate how this new injector service retrieves and writes these secrets for the applications to use.
»Prerequisites
This tutorial requires the Kubernetes command-line interface (CLI) and the Helm CLI installed, Minikube, and additional configuration to bring it all together.
Online tutorial: An interactive tutorial is also available if you do not wish to install the following resources. Click the Show Terminal button to start.
This tutorial was last tested 20 Jun 2020 on a macOS 10.15.5 using this configuration.
Docker version.
$ docker version
Client: Docker Engine - Community
Version: 19.03.8
## ...
Minikube version.
$ minikube version
minikube version: v1.11.0
commit: 57e2f55f47effe9ce396cea42a1e0eb4f611ebbd
Helm version.
$ helm version
version.BuildInfo{Version:"v3.2.1", GitCommit:"fe51cd1e31e6a202cba7dead9552a6d418ded79a", GitTreeState:"clean", GoVersion:"go1.13.10"}
These are recommended software versions and the output displayed may vary depending on your environment and the software versions you use.
First, follow the directions to install Minikube, including VirtualBox or similar.
Next, install kubectl CLI and helm CLI.
Install kubectl
with Homebrew.
$ brew install kubernetes-cli
Install helm
with Homebrew.
$ brew install helm
Next, retrieve the web application and additional configuration by cloning the hashicorp/vault-guides repository from GitHub.
$ git clone https://github.com/hashicorp/vault-guides.git
This repository contains supporting content for all of the Vault learn guides. The content specific to this tutorial can be found within a sub-directory.
Go into the
vault-guides/operations/provision-vault/kubernetes/minikube/vault-agent-sidecar
directory.
$ cd vault-guides/operations/provision-vault/kubernetes/minikube/vault-agent-sidecar
Working directory: This tutorial assumes that the remainder of commands are executed within this directory.
»Start Minikube
Minikube is a CLI tool that provisions and manages the lifecycle of single-node Kubernetes clusters locally inside Virtual Machines (VM) on your system.
Start a Kubernetes cluster.
$ minikube start
😄 minikube v1.11.0 on Darwin 10.15.5
✨ Automatically selected the hyperkit driver
👍 Starting control plane node minikube in cluster minikube
🔥 Creating hyperkit VM (CPUs=2, Memory=4000MB, Disk=20000MB) ...
🐳 Preparing Kubernetes v1.18.3 on Docker 19.03.8 ...
🔎 Verifying Kubernetes components...
🌟 Enabled addons: default-storageclass, storage-provisioner
🏄 Done! kubectl is now configured to use "minikube"
The initialization process takes several minutes as it retrieves any necessary dependencies and executes various container images.
Verify the status of the Minikube cluster.
$ minikube status
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
Additional waiting: Even if this last command completed successfully, you may have to wait for Minikube to be available. If an error is displayed, try again after a few minutes.
The host, kubelet, and apiserver report that they are running. The kubectl
, a
command line interface (CLI) for running commands against Kubernetes cluster, is
also configured to communicate with this recently started cluster.
Minikube provides a visual representation of the status in a web-based dashboard. This interface displays the cluster activity in a visual interface that can assist in delving into the issues affecting it.
In another terminal, launch the minikube dashboard.
$ minikube dashboard
The operating system's default browser opens and displays the dashboard.
»Install the Vault Helm chart
The recommended way to run Vault on Kubernetes is via the Helm chart. Helm is a package manager that installs and configures all the necessary components to run Vault in several different modes. A Helm chart includes templates that enable conditional and parameterized execution. These parameters can be set through command-line arguments or defined in YAML.
Add the HashiCorp Helm repository.
$ helm repo add hashicorp https://helm.releases.hashicorp.com
"hashicorp" has been added to your repositories
Install the latest version of the Vault server running in development mode.
$ helm install vault hashicorp/vault --set "server.dev.enabled=true"
NAME: vault
## ...
The Vault pod and Vault Agent Injector pod are deployed in the default namespace.
Display all the pods within the default namespace.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
vault-0 1/1 Running 0 80s
vault-agent-injector-5945fb98b5-tpglz 1/1 Running 0 80s
The vault-0
pod runs a Vault server in development mode. The
vault-agent-injector
pod performs the injection based on the annotations
present or patched on a deployment.
Development mode: Running a Vault server in development is automatically initialized and unsealed. This is ideal in a learning environment but NOT recommended for a production environment.
Wait until the vault-0
pod and vault-agent-injector
pod are running and
ready (1/1
).
»Set a secret in Vault
The applications that you deploy in the Inject secrets into the
pod section expect Vault to store a username and
password stored at the path internal/database/config
. To create this secret
requires that a key-value secret
engine is enabled and a
username and password is put at the specified path.
Start an interactive shell session on the vault-0
pod.
$ kubectl exec -it vault-0 -- /bin/sh
/ $
Your system prompt is replaced with a new prompt / $
. Commands issued at this
prompt are executed on the vault-0
container.
Enable kv-v2 secrets at the path internal
.
$ vault secrets enable -path=internal kv-v2
Success! Enabled the kv-v2 secrets engine at: internal/
Learn more: This tutorial focuses on Vault's integration with Kubernetes and not interacting the key-value secrets engine. For more information refer to the Static Secrets: Key/Value Secret tutorial.
Create a secret at path internal/database/config
with a username
and
password
.
$ vault kv put internal/database/config username="db-readonly-username" password="db-secret-password"
Key Value
--- -----
created_time 2020-03-25T19:03:57.127711644Z
deletion_time n/a
destroyed false
version 1
Verify that the secret is defined at the path internal/database/config
.
$ vault kv get internal/database/config
====== Metadata ======
Key Value
--- -----
created_time 2020-03-25T19:03:57.127711644Z
deletion_time n/a
destroyed false
version 1
====== Data ======
Key Value
--- -----
password db-secret-password
username db-readonly-username
The secret is ready for the application.
Lastly, exit the vault-0
pod.
$ exit
»Configure Kubernetes authentication
Vault provides a Kubernetes authentication method that enables clients to authenticate with a Kubernetes Service Account Token. This token is provided to each pod when it is created.
Start an interactive shell session on the vault-0
pod.
$ kubectl exec -it vault-0 -- /bin/sh
/ $
Your system prompt is replaced with a new prompt / $
. Commands issued at this
prompt are executed on the vault-0
container.
Enable the Kubernetes authentication method.
$ vault auth enable kubernetes
Success! Enabled kubernetes auth method at: kubernetes/
Vault accepts this service token from any client within the Kubernetes cluster. During authentication, Vault verifies that the service account token is valid by querying a configured Kubernetes endpoint.
Configure the Kubernetes authentication method to use the service account token, the location of the Kubernetes host, and its certificate.
$ vault write auth/kubernetes/config \
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
Success! Data written to: auth/kubernetes/config
The token_reviewer_jwt
and kubernetes_ca_cert
are mounted to the container
by Kubernetes when it is created. The environment variable
KUBERNETES_PORT_443_TCP_ADDR
is defined and references the internal network
address of the Kubernetes host.
For a client to read the secret data defined at internal/database/config
,
requires that the read capability be granted for the path
internal/data/database/config
. This is an example of a
policy. A policy
defines a set of capabilities.
Write out the policy named internal-app
that enables the read
capability
for secrets at path internal/data/database/config
.
$ vault policy write internal-app - <<EOF
path "internal/data/database/config" {
capabilities = ["read"]
}
EOF
Success! Uploaded policy: internal-app
Create a Kubernetes authentication role named internal-app
.
$ vault write auth/kubernetes/role/internal-app \
bound_service_account_names=internal-app \
bound_service_account_namespaces=default \
policies=internal-app \
ttl=24h
Success! Data written to: auth/kubernetes/role/internal-app
The role connects the Kubernetes service account, internal-app
, and namespace,
default
, with the Vault policy, internal-app
. The tokens returned after
authentication are valid for 24 hours.
Lastly, exit the vault-0
pod.
$ exit
»Define a Kubernetes service account
The Vault Kubernetes authentication role defined a Kubernetes service account
named internal-app
. This service account does not yet exist.
Verify that the Kubernetes service account named internal-app
does not exist.
$ kubectl get serviceaccounts
NAME SECRETS AGE
default 1 43m
vault 1 34m
vault-agent-injector 1 34m
This service account does not exist.
Display the service account defined in service-account-internal-app.yml
.
$ cat service-account-internal-app.yml
apiVersion: v1
kind: ServiceAccount
metadata:
name: internal-app
This definition of the service account creates the account with the name
internal-app
.
Apply the service account definition to create it.
$ kubectl apply --filename service-account-internal-app.yml
serviceaccount/internal-app created
Verify that the service account has been created.
$ kubectl get serviceaccounts
NAME SECRETS AGE
default 1 52m
internal-app 1 13s
vault 1 43m
vault-agent-injector 1 43m
The name of the service account here aligns with the name assigned to the
bound_service_account_names
field when the internal-app
role was created.
»Launch an application
We've created a sample application, published it to DockerHub, and created a Kubernetes deployment that launches this application.
Display the deployment for the orgchart
application.
$ cat deployment-orgchart.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: orgchart
labels:
app: orgchart
spec:
selector:
matchLabels:
app: orgchart
replicas: 1
template:
metadata:
annotations:
labels:
app: orgchart
spec:
serviceAccountName: internal-app
containers:
- name: orgchart
image: jweissig/app:0.0.1
The name of this deployment is orgchart
. The
spec.template.spec.serviceAccountName
defines the service account
internal-app
to run this container.
Apply the deployment defined in deployment-orgchart.yml
.
$ kubectl apply --filename deployment-orgchart.yml
deployment.apps/orgchart created
The orgchart
pod within the default namespace.
Get all the pods within the default namespace.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
orgchart-69697d9598-l878s 1/1 Running 0 18s
vault-0 1/1 Running 0 58m
vault-agent-injector-5945fb98b5-tpglz 1/1 Running 0 58m
The orgchart pod is displayed here as the pod prefixed with orgchart
.
Additional waiting: The deployment of the pod requires the retrieval
of the application container from Docker Hub. This
displays the STATUS of ContainerCreating
. The pod reports that it is not
ready (0/1
).
The Vault-Agent injector looks for deployments that define specific annotations.
None of these annotations exist within the current deployment. This means that
no secrets are present on the orgchart
container within the orgchart
pod.
Verify that no secrets are written to the orgchart
container in the
orgchart
pod.
$ kubectl exec \
$(kubectl get pod -l app=orgchart -o jsonpath="{.items[0].metadata.name}") \
--container orgchart -- ls /vault/secrets
ls: /vault/secrets: No such file or directory
command terminated with exit code 1
The output displays that there is no such file or directory named
/vault/secrets
.
»Inject secrets into the pod
The deployment is running the pod with the internal-app
Kubernetes service
account in the default namespace. The Vault Agent Injector only modifies a
deployment if it contains a specific set of annotations. An existing deployment
may have its definition patched to include the necessary annotations.
Display the deployment patch patch-inject-secrets.yml
.
$ cat patch-inject-secrets.yml
spec:
template:
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "internal-app"
vault.hashicorp.com/agent-inject-secret-database-config.txt: "internal/data/database/config"
These
annotations
define a partial structure of the deployment schema and are prefixed with
vault.hashicorp.com
.
agent-inject
enables the Vault Agent Injector servicerole
is the Vault Kubernetes authentication roleagent-inject-secret-FILEPATH
prefixes the path of the file,database-config.txt
written to the/vault/secrets
directory. The value is the path to the secret defined in Vault.
Patch the orgchart
deployment defined in patch-inject-secrets.yml
.
$ kubectl patch deployment orgchart --patch "$(cat patch-inject-secrets.yml)"
deployment.apps/orgchart patched
A new orgchart
pod starts alongside the existing pod. When it is ready the
original terminates and removes itself from the list of active pods.
Get all the pods within the default namespace.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
orgchart-599cb74d9c-s8hhm 0/2 Init:0/1 0 23s
orgchart-69697d9598-l878s 1/1 Running 0 20m
vault-0 1/1 Running 0 78m
vault-agent-injector-5945fb98b5-tpglz 1/1 Running 0 78m
Wait until the re-deployed orgchart
pod reports that
it is
Running
and ready (2/2
).
This new pod now launches two containers. The application container, named
orgchart
, and the Vault Agent container, named vault-agent
.
Display the logs of the vault-agent
container in the new orgchart
pod.
$ kubectl logs \
$(kubectl get pod -l app=orgchart -o jsonpath="{.items[0].metadata.name}") \
--container vault-agent
## ...
Vault Agent manages the token lifecycle and the secret retrieval. The secret is
rendered in the orgchart
container at the path
/vault/secrets/database-config.txt
.
Finally, display the secret written to the orgchart
container.
$ kubectl exec \
$(kubectl get pod -l app=orgchart -o jsonpath="{.items[0].metadata.name}") \
--container orgchart -- cat /vault/secrets/database-config.txt
data: map[password:db-secret-password username:db-readonly-user]
metadata: map[created_time:2019-12-20T18:17:50.930264759Z deletion_time: destroyed:false version:2]
The unformatted secret data is present on the container.
»Apply a template to the injected secrets
The structure of the injected secrets may need to be structured in a way for an application to use. Before writing the secrets to the file system a template can structure the data. To apply this template a new set of annotations need to be applied.
Display the annotations file that contains a template definition.
$ cat patch-inject-secrets-as-template.yml
spec:
template:
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-inject-status: "update"
vault.hashicorp.com/role: "internal-app"
vault.hashicorp.com/agent-inject-secret-database-config.txt: "internal/data/database/config"
vault.hashicorp.com/agent-inject-template-database-config.txt: |
{{- with secret "internal/data/database/config" -}}
postgresql://{{ .Data.data.username }}:{{ .Data.data.password }}@postgres:5432/wizard
{{- end -}}
This patch contains two new annotations:
agent-inject-status
set toupdate
informs the injector reinject these values.agent-inject-template-FILEPATH
prefixes the file path. The value defines the Vault Agent template to apply to the secret's data.
The template formats the username and password as a PostgreSQL connection string.
Apply the updated annotations.
$ kubectl patch deployment orgchart --patch "$(cat patch-inject-secrets-as-template.yml)"
deployment.apps/exampleapp patched
Get all the pods within the default namespace.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
orgchart-554db4579d-w6565 2/2 Running 0 16s
vault-0 1/1 Running 0 126m
vault-agent-injector-5945fb98b5-tpglz 1/1 Running 0 126m
Wait until the re-deployed orgchart
pod reports that
it is
Running
and ready (2/2
).
Finally, display the secret written to the orgchart
container in the
orgchart
pod.
$ kubectl exec \
$(kubectl get pod -l app=orgchart -o jsonpath="{.items[0].metadata.name}") \
-c orgchart -- cat /vault/secrets/database-config.txt
postgresql://db-readonly-user:db-secret-password@postgres:5432/wizard
The secrets are rendered in a PostgreSQL connection string is present on the container.
»Pod with annotations
The annotations may patch these secrets into any deployment. Pods require that the annotations be included in their initial definition.
Display the pod definition for the payroll
application.
$ cat pod-payroll.yml
apiVersion: v1
kind: Pod
metadata:
name: payroll
labels:
app: payroll
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "internal-app"
vault.hashicorp.com/agent-inject-secret-database-config.txt: "internal/data/database/config"
vault.hashicorp.com/agent-inject-template-database-config.txt: |
{{- with secret "internal/data/database/config" -}}
postgresql://{{ .Data.data.username }}:{{ .Data.data.password }}@postgres:5432/wizard
{{- end -}}
spec:
serviceAccountName: internal-app
containers:
- name: payroll
image: jweissig/app:0.0.1
Apply the pod defined in pod-payroll.yml
.
$ kubectl apply --filename pod-payroll.yml
pod/payroll created
Get all the pods within the default namespace.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
orgchart-554db4579d-w6565 2/2 Running 0 29m
payroll 2/2 Running 0 12s
vault-0 1/1 Running 0 155m
vault-agent-injector-5945fb98b5-tpglz 1/1 Running 0 155m
Wait until the payroll
pod reports that
it is
Running
and ready (2/2
).
Finally, display the secret written to the payroll
container in the payroll
pod.
$ kubectl exec \
payroll \
--container payroll -- cat /vault/secrets/database-config.txt
postgresql://db-readonly-user:db-secret-password@postgres:5432/wizard
The secrets are rendered in a PostgreSQL connection string is present on the container.
»Secrets are bound to the service account
Pods run with a Kubernetes service account other than the ones defined in the Vault Kubernetes authentication role are NOT able to access the secrets defined at that path.
Display the deployment and service account for the website
application.
$ cat deployment-website.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: website
labels:
app: website
spec:
selector:
matchLabels:
app: website
replicas: 1
template:
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "internal-app"
vault.hashicorp.com/agent-inject-secret-database-config.txt: "internal/data/database/config"
vault.hashicorp.com/agent-inject-template-database-config.txt: |
{{- with secret "internal/data/database/config" -}}
postgresql://{{ .Data.data.username }}:{{ .Data.data.password }}@postgres:5432/wizard
{{- end -}}
labels:
app: website
spec:
# This service account does not have permission to request the secrets.
serviceAccountName: website
containers:
- name: website
image: jweissig/app:0.0.1
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: website
Apply the deployment and service account defined in deployment-website.yml
.
$ kubectl apply --filename deployment-website.yml
deployment.apps/website created
serviceaccount/website created
Get all the pods within the default namespace.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
orgchart-554db4579d-w6565 2/2 Running 0 29m
payroll 2/2 Running 0 12s
vault-0 1/1 Running 0 155m
vault-agent-injector-5945fb98b5-tpglz 1/1 Running 0 155m
website-7fc8b69645-527rf 0/2 Init:0/1 0 76s
The website
deployment creates a pod but it is NEVER ready.
Display the logs of the vault-agent-init
container in the website
pod.
$ kubectl logs \
$(kubectl get pod -l app=website -o jsonpath="{.items[0].metadata.name}") \
--container vault-agent-init
##...
[INFO] auth.handler: authenticating
[ERROR] auth.handler: error authenticating: error="Error making API request.
URL: PUT http://vault.default.svc:8200/v1/auth/kubernetes/login
Code: 500. Errors:
* service account name not authorized" backoff=1.562132589
The initialization process failed because the service account name is not
authorized. The service account, external-app
is not assigned to any Vault
Kubernetes authentication role. This failure to authenticate causes the
deployment to fail initialization.
Display the deployment patch patch-website.yml
.
$ cat patch-website.yml
spec:
template:
spec:
serviceAccountName: internal-app
The patch modifies the deployment definition to use the service account
internal-app
. This Kubernetes service account is authorized by the Vault
Kubernetes authentication role.
Patch the website
deployment defined in patch-website.yml
.
$ kubectl patch deployment website --patch "$(cat patch-website.yml)"
Get all the pods within the default namespace.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
orgchart-554db4579d-w6565 2/2 Running 0 29m
payroll 2/2 Running 0 12s
vault-0 1/1 Running 0 155m
vault-agent-injector-5945fb98b5-tpglz 1/1 Running 0 155m
website-788d689b87-tll2r 2/2 Running 0 27s
Wait until the website
pod reports that it is
Running
and ready (2/2
).
Finally, display the secret written to the website
container in the website
pod.
$ kubectl exec \
$(kubectl get pod -l app=website -o jsonpath="{.items[0].metadata.name}") \
--container website -- cat /vault/secrets/database-config.txt; echo
postgresql://db-readonly-user:db-secret-password@postgres:5432/wizard
The secrets are rendered in a PostgreSQL connection string is present on the container.
Vault Kubernetes Roles: Alternatively, you can define a new Vault Kubernetes role, that enables the original service account access, and patch the deployment.
»Secrets are bound to the namespace
Pods run in a namespace other than the ones defined in the Vault Kubernetes authentication role are NOT able to access the secrets defined at that path.
Create the offsite
namespace.
$ kubectl create namespace offsite
namespace/offsite created
Set the current context to the offsite namespace.
$ kubectl config set-context --current --namespace offsite
Context "minikube" modified.
Apply the internal-app
service account to create it within the offsite
namespace.
$ kubectl apply --filename service-account-internal-app.yml
serviceaccount/internal-app created
Display the deployment for the issues
application.
$ cat deployment-issues.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: issues
labels:
app: issues
spec:
selector:
matchLabels:
app: issues
replicas: 1
template:
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "internal-app"
vault.hashicorp.com/agent-inject-secret-database-config.txt: "internal/data/database/config"
vault.hashicorp.com/agent-inject-template-database-config.txt: |
{{- with secret "internal/data/database/config" -}}
postgresql://{{ .Data.data.username }}:{{ .Data.data.password }}@postgres:5432/wizard
{{- end -}}
labels:
app: issues
spec:
serviceAccountName: internal-app
containers:
- name: issues
image: jweissig/app:0.0.1
Apply the deployment defined in deployment-issues.yml
.
$ kubectl apply --filename deployment-issues.yml
deployment.apps/issues created
Get all the pods within the offsite namespace.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
issues-79d8bf7cdf-dkdlq 0/2 Init:0/1 0 3s
Current context: The same command is issued but the results are different because you are now in a different namespace.
The issues
deployment creates a pod but it is NEVER ready.
Display the logs of the vault-agent-init
container in the issues
pod.
$ kubectl logs \
$(kubectl get pod -l app=issues -o jsonpath="{.items[0].metadata.name}") \
--container vault-agent-init
##...
[INFO] auth.handler: authenticating
[ERROR] auth.handler: error authenticating: error="Error making API request.
URL: PUT http://vault.default.svc:8200/v1/auth/kubernetes/login
Code: 500. Errors:
* namespace not authorized" backoff=1.9882590740000001
The initialization process fails because the namespace is not authorized. The
namespace, offsite
is not assigned to any Vault Kubernetes authentication
role. This failure to authenticate causes the deployment to fail initialization.
Start an interactive shell session on the vault-0
pod in the default
namespace.
$ kubectl exec --namespace default -it vault-0 -- /bin/sh
/ $
Your system prompt is replaced with a new prompt / $
. Commands issued at this
prompt are executed on the vault-0
container.
Create a Kubernetes authentication role named offsite-app
.
$ vault write auth/kubernetes/role/offsite-app \
bound_service_account_names=internal-app \
bound_service_account_namespaces=offsite \
policies=internal-app \
ttl=24h
Success! Data written to: auth/kubernetes/role/offsite-app
Exit the vault-0
pod.
$ exit
Display the deployment patch patch-issues.yml
.
$ cat patch-issues.yml
spec:
template:
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/agent-inject-status: "update"
vault.hashicorp.com/role: "offsite-app"
vault.hashicorp.com/agent-inject-secret-database-config.txt: "internal/data/database/config"
vault.hashicorp.com/agent-inject-template-database-config.txt: |
{{- with secret "internal/data/database/config" -}}
postgresql://{{ .Data.data.username }}:{{ .Data.data.password }}@postgres:5432/wizard
{{- end -}}
The patch performs an update to set the vault.hashicorp.com/role
to the
Vault Kubernetes role offsite-app
.
Patch the issues
deployment defined in patch-issues.yml
.
$ kubectl patch deployment issues --patch "$(cat patch-issues.yml)"
deployment.apps/issues patched
A new issues
pod starts alongside the existing pod. When it is ready the
original terminates and removes itself from the list of active pods.
Get all the pods within the offsite namespace.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
issues-7fd66f98f6-ffzh7 2/2 Running 0 94s
Wait until the re-deployed issues
pod reports that
it is
Running
and ready (2/2
).
Finally, display the secret written to the issues
container in the issues
pod.
$ kubectl exec \
$(kubectl get pod -l app=issues -o jsonpath="{.items[0].metadata.name}") \
--container issues -- cat /vault/secrets/database-config.txt; echo
postgresql://db-readonly-user:db-secret-password@postgres:5432/wizard
The secrets are rendered in a PostgreSQL connection string is present on the container.
»Next Steps
You launched Vault and the injector service with the Vault Helm chart. Learn more about the Vault Helm chart by reading the documentation, exploring the project source code, reading the blog post announcing the "Injecting Vault Secrets into Kubernetes Pods via a Sidecar", or the documentation for Agent Sidecar Injector
Then you deployed several applications to demonstrate how this new injector service retrieves and writes these secrets for the applications to use. Explore how pods can retrieve them directly via network requests or secrets mounted on ephemeral volumes.