Vault installation to Google Kubernetes Engine via Helm
Google Kubernetes Engine (GKE) can run Vault in its secured and managed Kubernetes service in standard or autopilot mode. Standard mode gives you the flexibility to configure the cluster's underlying infrastructure while autopilot mode gives you an optimized cluster with a hands-off experience.
In this tutorial, you create a cluster in GKE, install Vault in high-availability (HA) mode via the Helm chart and then configure the authentication between Vault and the cluster. Then you deploy a web application with deployment annotations so the application's secrets are installed via the Vault Agent injector service.
Prerequisites
This tutorial requires a Google Cloud account, Google Cloud command-line interface (CLI), Kubernetes CLI and the Helm CLI.
First, create a Google Cloud account.
Next, install Google Cloud CLI, kubectl CLI and helm CLI.
Next, connect the gcloud
CLI with your Google account.
This command launches the browser and requires that you authenticate with your Google account credentials.
Next, initialize the gcloud
CLI.
This initialization process may ask you to create a Google Cloud project. A project is a uniquely identified namespace that organizes all your Google Cloud resources. If you already have a project associated with your account, it may be important to create a new project.
If required, create a Google Cloud project with a unique identifier.
The gcloud
CLI manages Google Cloud resources for the project you select as
your current project.
If you created a project, you need to set this project as your current project.
The project may create resources within a variety of different compute zones spread across the world.
Display all the possible compute zones.
The output displays a table of the compute zones with their name and current status.
Set a default compute zone and region from the list with the UP status.
Start cluster
For a project to create a Kubernetes cluster requires that the container service is enabled.
Enable the Google container service.
A Vault cluster that is launched in high-availability requires a Kubernetes cluster with three nodes. You can manually create these nodes or use the AutoPilot mode.
Create a cluster in Autopilot mode named learn-vault
.
The cluster is created, deployed and then health-checked. When the cluster is
ready the command modifies the kubectl
configuration so that the commands you
issue are performed against that cluster.
Managing multiple clusters
kubectl
enables you to manage multiple
clusters
through the context configuration. You display the available contexts kubectl config get-contexts
and set the context by name kubectl config use-context NAME
.
Display the nodes of the cluster.
Autopilot displays a smaller set of nodes but more are provisioned as needed.
The cluster is ready.
Install the Vault Helm chart
The recommended way to run Vault on Kubernetes is via the Helm chart.
Add the HashiCorp Helm repository.
Update all the repositories to ensure helm
is aware of the latest versions.
Search for all the Vault Helm chart versions.
The Vault Helm chart contains all the necessary components to run Vault in several different modes.
Default behavior
By default, it launches Vault on a single pod in standalone mode with a file storage backend. Enabling high-availability with Raft Integrated Storage requires that you override these defaults.
Install the latest version of the Vault Helm chart in HA mode with integrated storage.
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
, and vault-2
pods deployed run a Vault server and
report that they are Running
but that they are not ready (0/1
). This is
because the status check defined in a
readinessProbe
returns a non-zero exit code.
The vault-agent-injector
pod deployed is a Kubernetes Mutation Webhook
Controller. The controller intercepts pod events and applies mutations to the
pod if specific annotations exist within the request.
Retrieve the status of Vault on the vault-0
pod.
The status command reports that Vault is not initialized and that it is sealed. For Vault to authenticate with Kubernetes and manage secrets requires that that is initialized and unsealed.
Initialize and unseal one Vault pod
Vault starts uninitialized and in the sealed state. Prior to initialization the Integrated Storage backend 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.
Retrieve the status of Vault on the vault-0
pod.
The Vault server is initialized and unsealed.
Join the other Vaults to the Vault cluster
The Vault server running on the vault-0
pod is a Vault HA cluster with a
single node. To display the list of nodes requires that you are logging in with
the root token.
Display the root token found in cluster-keys.json
.
Create a variable named CLUSTER_ROOT_TOKEN
to capture the Vault unseal key.
Login with the root token on the vault-0
pod.
Insecure operation
The login command stores the root token in a file for the container user. Subsequent commands are executed with that token. This approach is only used here to simplify the cluster configuration demonstration.
List all the nodes within the Vault cluster for the vault-0
pod.
This displays the one node within the Vault cluster. This cluster is addressable
through the Kubernetes service vault-0.vault-internal
created by the Helm
chart. The Vault servers on the other pods need to join this cluster and be
unsealed.
Join the Vault server on vault-1
to the Vault cluster.
This Vault server joins the cluster sealed. To unseal the Vault server requires
the same unseal key, VAULT_UNSEAL_KEY
, provided to the first Vault server.
Unseal the Vault server on vault-1
with the unseal key.
The Vault server on vault-1
is now a functional node within the Vault cluster.
Join the Vault server on vault-2
to the Vault cluster.
Unseal the Vault server on vault-2
with the unseal key.
The Vault server on vault-2
is now a functional node within the Vault cluster.
List all the nodes within the Vault cluster for the vault-0
pod.
This displays all three nodes within the Vault cluster.
Get all the pods within the default namespace.
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 Deploy 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.
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 kv-v2 secrets at the path secret
.
Create a secret at path secret/devwebapp/config
with a username
and
password
.
Verify that the secret is defined at the path secret/data/devwebapp/config
.
Learn more
For more information refer to the Versioned Key/Value Secrets Engine tutorial.
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 a service token from any client within the Kubernetes cluster. During authentication, Vault verifies that the service account token is valid by querying a token review Kubernetes endpoint.
Configure the Kubernetes authentication method to use the location of the Kubernetes API. It will automatically use the pod's own identity to authenticate with Kubernetes when querying the token review API.
For the best compatibility with recent Kubernetes versions, ensure you are using Vault v1.9.3 or greater.
The environment variable KUBERNETES_PORT_443_TCP_ADDR
is defined and references
the internal network address of the Kubernetes host.
For a client of the Vault server to read the secret data defined in the Set a
secret in Vault step requires that the read
capability be granted for the path secret/data/devwebapp/config
.
Write out the policy named devwebapp
that enables the read
capability
for secrets at path secret/data/devwebapp/config
Create a Kubernetes authentication role named devweb-app
.
The role connects a Kubernetes service account, internal-app
(created in the
next step), and namespace, default
, with the Vault policy, devwebapp
. The
tokens returned after authentication are valid for 24 hours.
Lastly, exit the vault-0
pod.
Deploy web application
The web application pod requires the creation of the internal-app
Kubernetes
service account specified in the Vault Kubernetes authentication role created in
the Configure Kubernetes authentication
step.
Create a Kubernetes service account named internal-app
.
Define a pod named devwebapp
with the web application.
This definition creates a pod with the specified container running with the
internal-app
Kubernetes service account. The container within the pod is
unaware of the Vault cluster. The Vault Injector service reads the
annotations
to find the secret path, stored within Vault at secret/data/devwebapp/config
and the file location, /vault/secrets/secret-credentials.txt
, to mount
that secret with the pod.
Learn more
For more information about annotations refer to the Injecting Secrets into Kubernetes Pods via Vault Agent Injector tutorial.
Create the devwebapp
pod.
Get all the pods within the default namespace.
Wait until the devwebapp
pod reports that is running and ready (2/2
).
Display the secrets written to the file /vault/secrets/secret-credentials.txt
on the devwebapp
pod.
The result displays the unformatted secret data present on the container.
Format data
A template can be applied to structure this data to meet the needs of the application.
Clean up
Destroy the cluster.
The cluster is destroyed.
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.
GKE provides the autopilot and standard modes to manage the underlying infrastructure. Learn more about these modes by reading the Autopilot mode.
The pod you deployed used annotations to inject the secret into the file system. Explore how pods can retrieve secrets through the Vault Injector service via annotations, or secrets mounted on ephemeral volumes.