Manage Kubernetes native secrets with the Vault Secrets Operator
Challenge
Vault offers a complete solution for secrets lifecycle management, but that requires developers and operators to learn a new tool. Instead, developers want a cloud native way to access the secrets through Kubernetes and have no need to understand Vault in great depth. Vault Secrets Operator (VSO) updates Kubernetes native secrets. The user accesses Kubernetes native secrets managed on the backend by HashiCorp Vault.
Solution
A Kubernetes operator is a software extension that uses custom resources to manage applications hosted on Kubernetes.
The Vault Secrets Operator is a Kubernetes operator that syncs secrets between Vault and Kubernetes natively without requiring the users to learn details of Vault use.
The Vault secrets operator supports kv-v1 and kv-v2, TLS certificates in PKI and full range of static and dynamic secrets.
The Vault Secrets Operator syncs the secrets between Vault and the Kubernetes secrets in a specified namespace. Within that namespace, applications have access to the secrets. The secrets are still managed by Vault, but accessed through the standard way on Kubernetes.
Launch Terminal
This tutorial includes a free interactive command-line lab that lets you follow along on actual cloud infrastructure.
Prerequisites
- Docker
- Helm CLI
- k9s
- Kubernetes command-line interface (CLI)
- minikube
- Recent version of the Vault binary installed. Refer to the Getting Started tutorial, and confirm you areusing a version that supports VSO: please see Supported Vault versions.
- Vault Enterprise requires a valid license.
Install supporting tools
This tutorial was last tested 27 June 2023 on a macOS 13.3.1 using the following software versions.
Clone the GitHub repository
Clone the repository at learn-vault-secrets-operator.
Move into that folder.
Start minikube
Minikube allows you to run a miniature Kubernetes cluster on your local machine.
Create a minikube cluster.
The output should resemble the following:
You have created a Kubernetes cluster running on Docker.
Install Vault cluster
Using Helm install Vault on a local instance of minikube. In Kubernetes, install Vault on it's own virtual cluster called a namespace.
If you have not already, add the HashiCorp Repo.
Update to the latest version of the HashiCorp Helm charts, update the repository.
Details of the output might differ, the important thing is the Update Complete message.
Determine the latest version of Vault.
Vault Secrets Operator supports the latest three versions of Vault. Please see Supported Vault versions for details.
Using the YAML file in the appropriate sub-folder, install Vault on your minikube cluster
The output should resemble the following:
Wait until the Vault pods are Ready 1/1 and status is Running.
Configure Vault
Here you connect to the Vault instance on minikube, enable and configure Kubernetes authentication, KV secrets engine, a role and policy for Kubernetes, and create a static secret.
Connect to the Vault instance. Until you
exit
you will be executing from inside the Vault instance.Move into the
tmp
directory.Enable the Kubernetes auth method.
Configure the auth method.
The output should resemble the following:
Enable the kv v2 Secrets Engine.
Create a JSON file with a Vault policy.
After uploading the Vault policy, it allows reading of the
webapp/config
secret in thekvv2
secrets engine mount.Create a role in Vault to enable access to secrets within the kv v2 secrets engine.
The output should resemble the following:
Notice that the bound_service_account_namespaces is app, limiting which namespace the secret is synced to.
Create a secret.
Exit the Vault instance.
Install the Vault Secrets Operator
Use Helm to deploy the Vault Secrets Operator.
Examine the file
vault-operator-values.yaml
for the values that this tutorial uses for VSO:For more details on these values see the
values.yaml
file for the Vault Secrets Operator Helm chart.
Deploy and sync a secret
In this section you will set up a namespace with a Kubernetes secret. The Vault Secrets Operator is configured to manage that secret.
Create a namespace called app on your Kubernetes cluster.
Set up Kubernetes authentication for the secret.
HCP Vault Dedicated
If you are using HCP Vault Dedicated, similar to Vault enterprise you will need to add the
namespace
parameter to thespec
field in thevault-auth-static.yaml
file.Create the secret names
secretkv
in the app namespace.If you examine the
static-secret.yaml
just used, look near the bottom.Either version you will find a field called
refreshAfter
. That fields determines how often to check the secret for updates. In the Vault community edition example, it set up to refresh after 30 seconds.In the Vault enterprise example the
refreshAfter
field is a fallback option, set to 1 hour. Since theinstantUpdates
is enabled, so therefreshAfter
field is ignored.
Rotate the static secret
In this section you use the k9s tool to display the secret. Then you use Vault to manually rotate the secret, and k9s to verify rotation of the Kubernetes secret.
Open a new terminal and start up
k9s
.If not already displayed, list the namespaces by typing
:ns
.Use the up and down arrows to choose the app namespace and press
enter
.This area is blank, so type in
:secrets
and press enter.Now the secrets named secretkv is displayed, highlight it.
Display the secret by pressing the
x
key.In the original terminal, connect to the Vault instance.
Rotate the secret.
Wait about 30 seconds before continuing to the next step, to allow for the secret to refresh.
Return to
k9s
, and escape back to the secret page and pressx
again to display the updated secret.The secret has changed, and now will be different than noted earlier.
At the first window, exit Vault.
Dynamic secrets
Manually rotating secrets is cumbersome and prone to human error. Vault dynamic secrets provides a solution for this.
Now you will create a dynamic secret with the database secrets engine. Dynamic secrets lifecycle is managed by Vault and will be automatically rotated. The lifecycle management includes deleting and recreating the secrets. In this section we will use the Vault Secrets Operator to rotate the Kubernetes secrets every 1 minute.
Install Postgres pod
You will create a pod and install PostGreSQL. PostGreSQL will later generate credentials for the database secrets engine.
Create a namespace for the PostGreSQL pod.
Add the Bitnami repository to your local Helm.
Install PostgreSQL.
The output should resemble the following:
Setup PostGreSQL
Connect to the Vault instance, and set up a database secrets engine in Vault with a corresponding role and policy.
Connect to the Vault instance.
Enable an instance of the Database Secrets Engine.
Configure the Database Secrets Engine.
The output should resemble the following:
Create a role for the PostgreSQL pod.
The output should resemble the following:
Note
Important: when you define the role in a production deployment, you must create user creation_statements, revocation_statements, renew_statements, and rotation_statements which are valid for the database you've configured. If you do not specify statements appropriate to creating, revoking, or rotating users, Vault inserts generic statements which can be unsuitable for your deployment.
Also, you do not want
default_ttl="1m"
ormax_ttl="1m"
set in production. This is too short and in production a longer TTL should be used. This tutorial is for demonstration purposes.Create the
demo-auth-policy-db
policy.The output should resemble the following:
Disconnect to the Vault instance.
Transit encryption
Vault Secrets Operator can be configured to maintain an internal, encrypted persistent cache of client tokens.
This is helpful for being able to transparently renew leases for dynamic secrets should the operator restart. Without using the client cache, the operator would need to fetch new client tokens on restarts, and re-issue credentials for dynamic secrets, causing downtime for applications. With transit encryption configured and enabled, the client token cache is end-to-end encrypted using Transit Encryption so that the persisted tokens cannot be accessed.
The Helm chart
vault-operator-values.yaml
already set up the Vault secrets operator for client token cache.Much of the remaining tutorial is setting up Vault to these specifications already present in
vault-operator-values.yaml
.The
clientCache
section has settings for the cache to use the direct encrypted mode.The
storageEncryption
sub-section specifies details of the transit secrets engine, authentication that is used by the transit secrets engine.transitMount
sets the transit secrets engine mount nameddemo-transit
.mount
sets the Kubernetes auth method engine nameddemo-auth-transit
used by thedemo-transit
.keyName
specifies a key namedvso-client-cache
used for encrypt/decrypt operations.kubernetes
sub-section configures the Vault Kubernetes auth method, specifying the role and the service account.
Refer to Vault Secrets Operator Helm chart section on
storageEncryption
documentation for details.Connect back to the Vault instance.
Enable an instance of the Transit Secrets Engine at the path
demo-transit
.Create a encryption key.
Create a policy for the operator role to access the encryption key.
The output should resemble the following:
Create Kubernetes auth role for the operator.
The output should resemble the following:
Setup dynamic secrets
Vault includes a number of dynamic secrets engines capable of generating temporary credentials for various applications. In this tutorial, Vault's dynamic secrets engine for PostgreSQL to generate temporary client credentials to the PostgreSQL database.
See Dynamic Secrets for another example.
Create a role to allow access to the Kubernetes secrets engine for the demo-ns
.
Create a new role for the dynamic secret.
The output should resemble the following:
Exit the shell.
Create the application
In this section you create a namespace demo-ns
that has a dynamic secret available, and an application to access it. By using this secret the application has access to PostgreSQL. Later you will use k9s
to examine the variable and verify that it automatically rotates.
Create a new namespace.
Create the app, Vault connection, authentication, service account and corresponding secrets.
Note
If you receive warning messages resembling the following:
Warning: resource
vaultauths/default
is missing thekubectl.kubernetes.io/last-applied-configuration
annotation. Thekubectl apply
requires this. Thekubectl apply
command should be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.No preexisting information for annotation
kubectl.kubernetes.io/last-applied-configuration
exists, therefore this first configuration and will be used to compare for changes later.
Examine the dynamic secret
Using k9s
, examine the dynamic secret and confirm the secrets change every minute.
Go back to the window with k9s and display all the available namespaces with the
:ns
command.Find and choose the demo-ns by highlighting it and pressing return.
Display the secrets in the demo-ns pod by typing
:secrets
and enter.Choose the first secret displayed and press
x
.The secrets should resemble the following, remember to note down the password displayed
Exit screen with escape key and wait a minimum of 60 seconds, and check the values once again with
x
. Notice the password has automatically changed.
Clean up
Delete the minikube cluster.
Additional discussion
A Kubernetes operator is a software extension that uses custom resources to manage applications hosted on Kubernetes. The Vault Secret Operator leverages HashiCorp Vault as a complete secrets management solution.
Secrets exist within Namespaces, which are virtual clusters with a Kubernetes Cluster. The secrets operator allows you to administer the secrets through Vault, but access them as a native Kubernetes primitive.
Kubernetes cluster administrators interested in using the Vault Secrets Operator to rotate Dynamic secrets are encouraged to look at the demo included with the source for the Vault Secrets Operator.
In this tutorial you began to learn about the Vault Secrets Operator by setting up a minikube cluster with a Vault instance and a Vault Secrets Operator controller, then created a secret in a namespace called app. Then you displayed the secret in k9s, and used Vault to rotate the secret. You then validated the change in the Vault secret value also changed the Kubernetes secret.
In the Dynamic Secrets section you set up a PostgreSQL pod, placeholder application and created a dynamic secret. Then, using k9s you watched the secret rotate automatically.
The Vault Secrets Operator is a Kubernetes operator pattern for use with HashiCorp Vault. It is responsible for syncing Vault secrets to Kubernetes Secrets natively.
Features of the Vault Secrets Operator include support for all secrets engines and Kubernetes, AWS, JWT and AppRole authentication to Vault.