Vault installation to minikube via Helm with Consul
Challenge
Running Vault on Kubernetes is generally the same as running it anywhere else. Kubernetes, as a container orchestration engine, eases some of the operational burdens and Helm charts provide the benefit of a refined interface when it comes to deploying Vault in a variety of different modes.
Solution
In this tutorial, you will set up Vault and its dependencies on Kubernetes with a Helm chart. Then you will integrate a web application that uses the Kubernetes service account token to authenticate with Vault and retrieve a secret.
Note
This tutorial creates a Vault cluster using Consul as the storage backend. To learn how to create a Vault cluster with Integrated Storage using the Vault Helm chart, see the Vault Installation to Minikube via Helm with Integrated Storage tutorial.
Prerequisites
This tutorial requires the Kubernetes command-line interface (CLI), Helm CLI , Minikube, Vault and Consul Helm charts, jq, the sample web application, and additional configuration to bring it all together. Instructions on how to install these are below.
This tutorial was last tested 23 May 2022 on a macOS 12.3.1 using the following configuration:
Docker:
Kubernetes-cli:
Helm:
Minikube:
These are recommended software versions and the output displayed may vary depending on your environment and the software versions you use.
If you do not already have these tools installed, please see below on how to insall them.
Install kubectl
with Homebrew.
Install helm
with Homebrew.
Install minikube
with Homebrew.
Install jq
with Homebrew.
Next, retrieve the web application and additional configuration by cloning the learn-vault-kubernetes-consul repository from GitHub.
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 learn-vault-kubernetes-consul
directory.
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 running inside Virtual Machines (VM) on your local system.
Start a Kubernetes cluster.
The initialization process takes several minutes as it retrieves any necessary dependencies and executes various container images.
Verify the status of the Minikube cluster.
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
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 be used to explore the issues affecting it.
In another terminal, launch the minikube dashboard.
The operating system's default browser opens and displays the dashboard.
Install the Consul Helm chart
Consul is a service mesh solution that launches with a key-value store. Vault requires a storage backend like Consul to manage its configuration and secrets when it is run in high-availability.
Integrated Storage
Vault running on Kubernetes also supports integrated storage. Explore setting up Vault in high-availability with Integrated Storage in the Vault Installation to Google Kubernetes Engine via Helm tutorial.
The recommended way to run Consul on Kubernetes is via the Helm chart. Helm is a package manager that installs and configures all the necessary components to run Consul 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.
Consul's Helm chart by default starts more services than required to act as Vault's storage backend.
Display the parameters in helm-consul-values.yml
.
Add the HashiCorp Helm repository.
Update all the repositories to ensure helm
is aware of the latest versions.
Install the latest version of the Consul Helm chart with parameters
helm-consul-values.yml
applied.
The installation of the Helm chart displays the name, namespace, status, and resources created. The server and client pods are deployed in the default namespace because no namespace was specified or configured as the default.
Get all the pods within the default namespace.
The Consul client and server pods are displayed here prefixed with consul
.
Wait until the server and client pods report that they are
Running
and ready (1/1
).
For more information refer to the Installing Consul to Minikube via Helm tutorial
Install the Vault Helm chart
The recommended way to run Vault on Kubernetes is via the Helm chart. This installs and configures all the necessary components to run Vault in several different modes.
Vault's Helm chart by default launches with a file storage backend. To utilize the Consul cluster as a storage backend requires Vault to be run in high-availability mode.
Display the parameters in helm-vault-values.yml
.
Install the latest version of the Vault Helm chart with parameters
helm-vault-values.yml
applied.
The Vault pods and Vault Agent Injector pod are deployed in the default namespace.
Get all the pods within the default namespace.
The vault-0
, vault-1
, vault-2
, and vault-agent-injector
pods are
deployed. The Vault servers report that they are Running
but they are not
ready (0/1
). That is because Vault in each pod is executes a status check
defined in a
readinessProbe.
Retrieve the status of Vault on the vault-0
pod.
The status command reports that Vault is not initialized and that it is sealed.
The web interface reports the same results.
The Vault server can be reached via the CLI and the web UI outside of the Kubernetes cluster if the Vault service running on port 8200 is forwarded.
In another terminal, port
forward
all requests made to http://localhost:8200
to the vault-0
pod on port 8200.
In a browser window, navigate to the UI at http://localhost:8200/ui
Initialize and unseal Vault
Vault starts uninitialized and in the sealed state. Prior to initialization the storage backend, Consul, is not prepared to receive data.
Initialize Vault with one key share and one key threshold.
The operator init
command
generates a root key that it disassembles into key shares -key-shares=1
and
then sets the number of key shares required to unseal Vault -key-threshold=1
.
These key shares are written to the output as unseal keys in JSON format
-format=json
. Here the output is redirected to a file named
cluster-keys.json
.
Display the unseal key found in cluster-keys.json
.
Insecure operation
Do not run an unsealed Vault in production with a single key share and a single key threshold. This approach is only used here to simplify the unsealing process for this demonstration.
Create a variable named VAULT_UNSEAL_KEY
to capture the Vault unseal key.
After initialization, Vault is configured to know where and how to access the storage, but does not know how to decrypt any of it. Unsealing is the process of constructing the root key necessary to read the decryption key to decrypt the data, allowing access to the Vault.
Unseal Vault running on the vault-0
pod.
The operator unseal
command reports that Vault is initialized and unsealed.
Insecure operation
Providing the unseal key with the command writes the key to your shell's history. This approach is only used here to simplify the unsealing process for this demonstration.
Unseal Vault running on the vault-1
pod.
Unseal Vault running on the vault-2
pod.
Verify all the Vault pods are running and ready.
The vault-0
, vault-1
, and vault-2
pods report that they are Running
and
ready (1/1
).
Set a secret in Vault
The web application that you deploy in the Launch a web
application section, expects Vault to store a
username and password at the path secret/webapp/config
. To create this secret
requires you to login with the root token, enable the key-value secret
engine, and store a
secret username and password at that defined path.
Vault generated an initial root token when it was initialized.
Display the root token found in cluster-keys.json
.
First, start an interactive shell session on the vault-0
pod.
Your system prompt is replaced with a new prompt / $
.
Note
the prompt within this section is shown as $
but the commands are
intended to be executed within this interactive shell on the vault-0
container.
Vault is now ready for you to login with the initial root token.
Vault requires clients to authenticate first before it allows any further actions. An unsealed Vault starts with the Token Auth Method enabled and generates an initial root token.
Login with the root token when prompted.
Enable kv-v2 secrets at the path secret
.
Learn more
This tutorial focuses on Vault's integration with Kubernetes and not interacting with the key-value secrets engine. For more information refer to the Versioned Key/value secrets engine tutorial.
Create a secret at path secret/webapp/config
with a username
and password
.
Verify that the secret is defined at the path secret/webapp/config
.
You successfully created the secret for the web application.
Lastly, exit the vault-0
pod.
Configure Kubernetes authentication
The initial root token is a privileged user that can perform any operation at any path. The web application only requires the ability to read secrets defined at a single path. This application should authenticate and be granted a token with limited access.
Best practice
We recommend that root tokens are used only for initial setup of an authentication method and policies. Afterwards they should be revoked. This tutorial does not show you how to revoke the root token.
Vault provides a Kubernetes authentication method that enables clients to authenticate with a Kubernetes Service Account Token.
First, start an interactive shell session on the vault-0
pod.
Your system prompt is replaced with a new prompt / $
.
Note
the prompt within this section is shown as $
but the commands are
intended to be executed within this interactive shell on the vault-0
container.
Enable the Kubernetes authentication method.
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 location of the Kubernetes API.
For the best compatibility with recent Kubernetes versions, ensure you are using Vault v1.10.3 or greater.
Successful output from this command resembles this example:
The environment variable KUBERNETES_PORT_443_TCP_ADDR
is defined and references
the internal network address of the Kubernetes host.
For a client to access the secret data defined, at secret/webapp/config
,
requires that the read capability be granted for the path
secret/data/webapp/config
. This is an example of a
policy. A policy
defines a set of capabilities.
Write out the policy named webapp
that enables the read
capability for
secrets at path secret/data/webapp/config
.
Successful output from this command resembles this example:
To apply this policy requires the authentication engine to define a role. A role binds policies and environment parameters together to create a login for the web application.
Create a Kubernetes authentication role, named webapp
, that connects the
Kubernetes service account name and webapp
policy.
Successful output from this command resembles this example:
The role connects the Kubernetes service account, vault
, and namespace,
default
, with the Vault policy, webapp
. The tokens returned after
authentication are valid for 24 hours.
Lastly, exit the vault-0
pod.
Launch a web application
We've created a web application, published it to DockerHub, and created a Kubernetes deployment that will run the application in your existing cluster. The example web application performs the single function of listening for HTTP requests. During a request it reads the Kubernetes service token, logs into Vault, and then requests the secret.
Display the webapp deployment definition in deployment-01-webapp.yml
.
The web application deployment defines a list of environment variables.
JWT_PATH
sets the path of the JSON web token (JWT) issued by Kubernetes. This token is used by the web application to authenticate with Vault.VAULT_ADDR
sets the address of the Vault service. The Helm chart defined a Kubernetes service namedvault
that forwards requests to its endpoints (i.e. The pods namedvault-0
,vault-1
, andvault-2
).SERVICE_PORT
sets the port that the service listens for incoming HTTP requests.
Deploy the webapp in Kubernetes by applying the file deployment-01-webapp.yml
.
The webapp runs as a pod within the default namespace.
Get all the pods within the default namespace.
The webapp pod is displayed here as the pod prefixed with webapp
.
Additional waiting
The deployment of the service requires the retrieval
of the web application container from Docker Hub.
This displays the STATUS of ContainerCreating
. The pod reports that it is
not ready (0/1
).
Wait until the webapp pod is running and ready (1/1
).
The webapp pod runs an HTTP service that is listening on port 8080.
In another terminal, port
forward
all requests made to http://localhost:8080
to the webapp pod on port 8080.
In the original terminal, perform a curl
request at http://localhost:8080
.
The web application running on port 8080 in the webapp pod:
- authenticates with the Kubernetes service account token
- receives a Vault token with the read capability at the
secret/data/webapp/config
path - retrieves the secrets from
secret/data/webapp/config
path - displays the secrets as JSON
Clean up
First, stop the running local Kubernetes cluster.
This deactivates minikube, and all pods still exist at this point.
Delete the local Kubernetes cluster.
Warning
minikube delete
removes the minikube deployment including all pods. Be sure you want everything removed before comtinuing.
Next steps
You launched Vault in high-availability mode with a Helm chart. Learn more about the Vault Helm chart by reading the documentation or exploring the project source code.
Vault running on Kubernetes also supports Integrated Storage. Explore setting up Vault in high-availability with Integrated Storage in the Vault Installation to Google Kubernetes Engine via Helm tutorial.
Then you deployed a web application that authenticated and requested a secret directly from Vault. Explore how pods can retrieve secrets through the Vault Injector service via annotations or secrets mounted on ephemeral volumes.
Finally, Consul is more than a storage backend for Vault. Explore running Consul on Minikube via Helm and its integrations with Kubernetes (including multi-cloud, service sync, and other features) in the Consul documentation.