Vault by HashiCorp is a powerful tool for managing secrets securely. In this tutorial, we’ll walk through setting up Vault on Kubernetes and using it with External Secrets to securely manage secrets in your applications.
Prerequisites:
Before we begin, ensure you have:
A running Kubernetes cluster.
kubectl installed and configured.
Helm installed on your system.
Step 1: Add the HashiCorp Helm Repository
HashiCorp provides a Helm chart for installing Vault. First, we need to add their repository to Helm:
$ helm repo add hashicorp https://helm.releases.hashicorp.com
$ helm repo update
This command adds HashiCorp’s Helm repository and updates your local Helm chart index.
Step 2: Install Vault Using Helm
Now, let’s deploy Vault into your Kubernetes cluster:
$ helm install vault hashicorp/vault -n vault --create-namespace
# vault: The name of the Helm release.
# hashicorp/vault: Specifies the Vault Helm chart from the HashiCorp repository.
# -n vault: Deploys Vault in the vault namespace.
# --create-namespace: Ensures the vault namespace is created if it doesn’t already exist.
Once this command runs successfully, Vault will be deployed, but it won’t be ready to use until initialized and unsealed.
Step 3: Initialize Vault
Vault must be initialized before it can store and manage secrets. Use the following command:
$ kubectl -n vault exec -it vault-0 -- vault operator init
This generates the unseal keys and an initial root token. Make sure to copy and securely store these tokens, as they are critical for accessing Vault.
You’ll see output like this:
Unseal Key 1: <key1>
Unseal Key 2: <key2>
Unseal Key 3: <key3>
Initial Root Token: <root-token>
Step 4: Unseal Vault
Vault operates in a “sealed” state by default. To make it operational, you need to “unseal” it using the keys generated earlier. Enter the Vault pod and unseal it:
$ kubectl -n vault exec -it vault-0 -- sh
Run the following commands to unseal Vault:
$ vault operator unseal
<insert key1>
$ vault operator unseal
<insert key2>
$ vault operator unseal
<insert key3>
You’ll paste each of the unseal keys when prompted. Once all keys are entered, the Vault becomes unsealed and operational.
Step 5: Log in to Vault
Log in using the initial root token:
$ vault login <INITIAL_ROOT_TOKEN>
Replace with the token you saved earlier.
Step 6: Enable a Secret Engine
Vault organizes secrets using engines. Here, we’ll enable the KV (Key-Value) engine:
$ vault secrets enable --version=2 --path=kv kv
# --version=2: Specifies that we’re using version 2 of the KV engine.
# --path=kv: Sets the mount path for the engine.
Step 7: Add Secrets to Vault
Let’s add some secrets to Vault. For example:
vault kv put -mount=kv dev-blog adminUser=test
vault kv put -mount=kv dev-blog adminPass='password'
Here:
# -mount=kv: Refers to the KV engine we enabled earlier.
# dev-blog: The path under which the secrets are stored.
# adminUser and adminPass: The key-value pairs representing your secrets.
You can repeat this process for all the secrets your application needs.
Step 8: Install External Secrets
External Secrets bridges the gap between Kubernetes and external secret management systems like HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, and others. Its primary purpose is to sync secrets from these external systems into Kubernetes-native secrets so that your applications can access them seamlessly.
In this setup, we’re using Vault as the secret management solution to securely store sensitive data. However, Kubernetes applications require secrets to be in the form of Kubernetes-native secrets. External Secrets acts as the intermediary that syncs secrets from Vault into Kubernetes.
Deploying External Secrets at this stage ensures that we have the required infrastructure to make Vault secrets accessible to our Kubernetes workloads. Once External Secrets is installed and configured, it will continuously monitor Vault for updates and keep Kubernetes secrets in sync with the external secret store.
This ensures that:
- Secrets are always up-to-date.
- Developers and applications don’t need to directly interact with Vault.
- The system remains secure, as Vault handles the secure storage and lifecycle of secrets, while Kubernetes secrets provide easy access for workloads.
$ helm install external-secrets external-secrets/external-secrets -n external-secrets --create-namespace
This installs External Secrets in the external-secrets namespace.
Step 9: Create a Vault Token Secret in Kubernetes
External Secrets needs a Vault token to authenticate. Create a Kubernetes secret with the token:
apiVersion: v1
data:
token: <your-token-base64>
kind: Secret
metadata:
name: vault-token
namespace: external-secrets
type: Opaque
Replace with the Base64-encoded token (use echo -n "token" | base64 to generate it).
Save this file as vaultTokenSecret.yaml and apply it:
$ kubectl -n external-secrets apply -f vaultTokenSecret.yaml
Step 10: Configure External Secrets to Access Vault
Now, create a ClusterSecretStore resource to configure External Secrets to communicate with Vault:
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
name: vault-backend-access
spec:
provider:
vault:
server: "https://vault.rajesh-kumar.in/"
path: "kv"
version: "v2"
auth:
tokenSecretRef:
name: "vault-token"
key: "token"
namespace: external-secrets
# server: The Vault server URL.
# path: The KV engine path (kv in our setup).
# auth.tokenSecretRef: Points to the secret containing the Vault token.
Save this as clusterSecretStore.yaml and apply it:
$ kubectl -n vault apply -f clusterSecretStore.yaml
Step 11: Verify and Use Secrets
With everything configured, you can create ExternalSecret resources to sync Vault secrets into Kubernetes secrets. For example:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: dev-blog-secrets
namespace: dev-blog-ns
spec:
secretStoreRef:
name: vault-backend-access
kind: ClusterSecretStore
target:
name: dev-blog-k8s-secret
data:
- secretKey: ADMIN_USER
remoteRef:
key: kv/dev-blog
property: adminUser
- secretKey: ADMIN_PASS
remoteRef:
key: kv/dev-blog
property: adminPass
Apply this file, and External Secrets will create an externalsecrets resource named dev-blog-secrets and a Kubernetes secret named dev-blog-k8s-secret in the dev-blog-ns namespace with the values pulled from Vault.
$ kubectl get externalsecret -n medium-blog-ns -o yaml
$ kubectl get secret -n medium-blog-ns -o yaml
Bonus: Expose Vault with Ingress Using Traefik
To make Vault accessible externally, we’ll expose it using an Ingress. This setup ensures that Vault is accessible through a friendly domain name (vault.rajesh-kumar.in) using HTTP.
Step 1: Ensure Traefik is Deployed
Traefik is a popular Kubernetes Ingress Controller that provides robust routing capabilities. If you don’t have Traefik installed, follow these steps:
Add the Traefik Helm Repository:
$ helm repo add traefik https://traefik.github.io/charts helm repo update
Install Traefik: Deploy Traefik to your cluster:
$ helm install traefik traefik/traefik --namespace traefik --create-namespace
Verify Installation: Ensure that Traefik is running:
$ kubectl get pods -n traefik
You should see pods like traefik- running successfully.
Expose Traefik’s Dashboard (Optional): To access Traefik’s dashboard, configure an additional IngressRoute (optional but useful for debugging).
Step 2: Expose Vault Using Ingress
Create a IngressRoute resource to expose Vault using Traefik. Save the following configuration as:vaultIngressRoute.yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: vault-ingressroute
namespace: vault
spec:
entryPoints:
- web
routes:
- match: Host(`vault.rajesh-kumar.in`)
kind: Rule
services:
- name: vault
port: 8200
scheme: http
Explanation:
entryPoints: web: Indicates that this route uses the HTTP entry point. You can modify this to websecure for HTTPS if TLS is configured.
Host(vault.rajesh-kumar.in): The domain that maps to the Vault service. Ensure this domain points to your Kubernetes cluster via DNS.
services: name: vault: Refers to the Vault service created by the Helm chart.
port: 8200: The default port Vault listens on.
Step 3: Apply the IngressRoute
Apply the IngressRoute configuration to your cluster:
$ kubectl apply -f vaultIngressRoute.yaml
Step 4: Update DNS or Hosts File
Point your domain (vault.rajesh-kumar.in) to the external IP of the Traefik LoadBalancer. If you’re testing locally, you can edit your /etc/hosts file to map the domain to the NODE IP:
<NODE-IP> vault.rajesh-kumar.in
Step 5: Access Vault
Now you should be able to access Vault in your browser using http://vault.rajesh-kumar.in
Optional: Secure with HTTPS
For production environments, it’s highly recommended to secure the Ingress with TLS. To enable HTTPS:
Configure a certificate (e.g., via Let’s Encrypt or a self-signed certificate).
Update the Traefik entry point to websecure.
Modify the IngressRoute to include a tls section.
Example:
spec:
entryPoints:
- websecure
tls:
secretName: mysecret-cert
routes:
- match: Host(`vault.rajesh-kumar.in`)
kind: Rule
services:
- name: vault
port: 8200
scheme: http
This ensures secure communication with Vault over HTTPS.
By exposing Vault with Ingress, you now have an external, accessible endpoint for managing secrets securely. This configuration is flexible, allowing further customization like TLS and additional routing rules to suit your needs.
Wrapping Up
Congratulations! You’ve successfully set up HashiCorp Vault on Kubernetes, stored secrets, and integrated it with External Secrets for secure secret management in Kubernetes.
This setup provides a robust foundation for securely managing application secrets, ensuring compliance, and enhancing security. Feel free to expand and customize this configuration for your specific use case!
Happy learning!
Thank you for reading!
Feel free to explore my articles for fascinating perspectives and useful suggestions. Let’s connect on LinkedIn. I’m eager to hear your thoughts and delve deeper into any discussions!
Top comments (0)