10 min to read
Installing and Configuring HashiCorp Vault on Kubernetes
A step-by-step guide to deploying Vault on Kind cluster

Overview
Following our previous post about Vault concepts, we’ll now explore how to install and configure Vault on a Kubernetes cluster using Kind. We’ll cover the complete setup process, including initialization, unsealing, and basic configuration.
Prerequisites
Setting up Kind Cluster
Create a Kind cluster with port forwarding for Vault (30000):
# cluster-3nodes.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30000
hostPort: 30000
listenAddress: "0.0.0.0"
protocol: TCP
- role: worker
- role: worker
# Create cluster
kind create cluster --name somaz-3nodes-kubernetes --config ./cluster-3nodes.yaml
# Verify nodes
kubectl get nodes
🔐 Vault Initialization Concepts
Before installation, it’s important to understand Vault’s initialization process.
In an HA environment with Raft storage backend, initialization generates two critical pieces:
1. Unseal Keys
{
"unseal_keys_b64": [
"xxxxx"
],
"unseal_shares": 1,
"unseal_threshold": 1
}
- Used to unlock Vault
- Can be split into multiple shares
- Required for unsealing after restarts
2. Root Token
{
"root_token": "hvs.xxxx"
}
- Master access key
- Provides full access to Vault
- Should be securely stored
📦 Installing Vault
1. Add Helm Repository
# Add HashiCorp helm repo
helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
# Verify repository
helm repo list
2. Install Vault
# Install with HA configuration
helm install vault hashicorp/vault \
--set='server.ha.enabled=true' \
--set='server.ha.raft.enabled=true' \
--namespace vault \
--create-namespace
3. Verify Installation
kubectl get pods -n vault
NAME READY STATUS RESTARTS AGE
vault-0 0/1 Running 0 82s
vault-1 0/1 Running 0 82s
vault-2 0/1 Running 0 82s
vault-agent-injector-7f7f68d457-kqlsh 1/1 Running 0 83s
Initializing and Unsealing Vault
1. Initialize Vault
# Initialize with single key share
kubectl exec vault-0 -n vault -- vault operator init \
-key-shares=1 \
-key-threshold=1 \
-format=json > cluster-keys.json
2. Capture Keys
# Store unseal key and root token
VAULT_UNSEAL_KEY=$(cat cluster-keys.json | jq -r ".unseal_keys_b64[]")
CLUSTER_ROOT_TOKEN=$(cat cluster-keys.json | jq -r ".root_token")
3. Unseal Vault Nodes
# Unseal vault-0
kubectl exec vault-0 -n vault -- vault operator unseal $VAULT_UNSEAL_KEY
# Join and unseal vault-1
kubectl exec vault-1 -n vault -- vault operator raft join http://vault-0.vault-internal:8200
kubectl exec vault-1 -n vault -- vault operator unseal $VAULT_UNSEAL_KEY
# Repeat for vault-2
kubectl exec vault-2 -n vault -- vault operator raft join http://vault-0.vault-internal:8200
kubectl exec vault-2 -n vault -- vault operator unseal $VAULT_UNSEAL_KEY
Accessing Vault UI
1. Configure NodePort Service
kubectl patch svc vault -n vault -p '{"spec": {"type": "NodePort", "ports": [{"nodePort": 30000, "port": 8200, "protocol": "TCP"}]}}'
2. Access UI
CLUSTER_ROOT_TOKEN=$(cat cluster-keys.json | jq -r ".root_token")
echo $CLUSTER_ROOT_TOKEN
hvs.bOXica9b3vWqfBaiZWfASOC1
- Open browser:
http://<node-ip>:30000
- Login using root token
create a user and access it with that user.
kubectl exec --stdin=true --tty=true vault-0 -n vault -- /bin/sh
# activate userpass
vault auth enable userpass
# create user example
vault write auth/userpass/users/<username> password=<password> policies=<policies>
# create user
vault write auth/userpass/users/somaz password=<password>
# login with user
vault login -method=userpass username=somaz password=<password>
Basic Secret Management
1. Enable KV Secrets Engine
- The kv-v2 engine is a key-vaule engine. It is usually used to use ID/PW or all key-value values.
# Enable KV version 2
kubectl exec -it vault-0 -n vault -- vault secrets enable -path=secret kv-v2
# Create a secret
kubectl exec -it vault-0 -n vault -- vault kv put secret/devdb/config \
username='somaz' \
password='somazpassword'
2. Create Policies
# Create read-only policy
kubectl exec -it vault-0 -n vault -- vault policy write devdb - <<EOF
path "secret/data/devdb/config" {
capabilities = ["read"]
}
EOF
3. Configure Kubernetes Authentication
The initial root token is a user who is authorized to perform all tasks on all paths.
Web applications only need the ability to read secrets defined in a single path.
This application must authenticate and receive tokens with limited access.
# Enable Kubernetes auth
kubectl exec -it vault-0 -n vault -- vault auth enable kubernetes
# Configure Kubernetes auth
kubectl exec -it vault-0 -n vault -- vault write auth/kubernetes/config \
kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443"
- Vault allows service tokens from all clients in the Kubernetes cluster.
- During authentication, Vault queries the token review Kubernetes endpoint to verify that the service account token is valid.
- Configure the Kubernetes authentication method to use the location of the Kubernetes API.
- When querying the token review API, it automatically uses Pod’s own ID to authenticate it to Kubernetes.
4. Create a policy that enables Vault devdb (example)
# create policy
vault policy write devdb - <<EOF
path "secret/data/devdb/config" {
capabilities = ["read"]
}
EOF
# list policy
vault policy list
default
devdb
root
# read policy
vault policy read devdb
path "secret/data/devdb/config" {
capabilities = ["read"]
}
5. Creates a Kubernetes authentication role.
vault write auth/kubernetes/role/db-app \\
bound_service_account_names=somaz-app \\
bound_service_account_namespaces=somaz \\
policies=devdb \\
ttl=24h
# read role
vault read auth/kubernetes/role/db-app
Deploy Web Application
1. Create a Kubernetes service account and Namespace
# create namespace
kubectl create namespace somaz
# create service account
kubectl create serviceaccount somaz-app -n somaz
2. Deploy the Web Application
# create yaml file
cat > devsomazapp.yaml <<EOF
---
apiVersion: v1
kind: Pod
metadata:
name: devsomazapp
labels:
app: devsomazapp
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "db-app"
vault.hashicorp.com/agent-inject-secret-credentials.txt: "secret/data/devdb/config"
spec:
serviceAccountName: somaz-app
containers:
- name: devsomazapp
image: jweissig/app:0.0.1
EOF
# create pod
k apply -f devsomazapp.yaml -n somaz
# read secret
k exec --stdin=true --tty=true devsomazapp -c devsomazapp -n somaz -- cat /vault/secrets/credentials.txt
3. Form of an Annotation
vault.hashicorp.com/agent-inject-secret-<unique-name>: /path/to/secret
If more than one Secret is designated as a policy, it should be set as follows.
vault.hashicorp.com/agent-inject-secret-devdb: secret/data/devdb/config
vault.hashicorp.com/agent-inject-secret-qadb: secret/data/qadb/config
vault.hashicorp.com/role: 'devdb-app'
Test Right Now.
# connect pod
kubectl exec --stdin=true --tty=true vault-0 -n vault -- /bin/sh
# create secret
vault kv put secret/qadb/config username='qasomaz' password='<password>'
# create policy
vault policy write qadb - <<EOF
path "secret/data/qadb/config" {
capabilities = ["read"]
}
EOF
# create role
vault write auth/kubernetes/role/db-app \\
bound_service_account_names=somaz-app \\
bound_service_account_namespaces=somaz \\
policies=devdb,qadb \\
ttl=24h
# read role
vault read auth/kubernetes/role/db-app
4. Change the Web Application yaml file and verify
# create yaml file
cat > devsomazapp.yaml <<EOF
---
apiVersion: v1
kind: Pod
metadata:
name: devsomazapp
labels:
app: devsomazapp
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "db-app"
vault.hashicorp.com/agent-inject-secret-devdb.txt: "secret/data/devdb/config"
vault.hashicorp.com/agent-inject-secret-qadb.txt: "secret/data/qadb/config"
spec:
serviceAccountName: somaz-app
containers:
- name: devsomazapp
image: jweissig/app:0.0.1
EOF
# create pod
k apply -f devsomazapp.yaml -n somaz
# restart pod
k delete po -n somaz devsomazapp
k apply -f devsomazapp.yaml -n somaz
# read secret
k exec --stdin=true --tty=true devsomazapp -c devsomazapp -n somaz -- ls /vault/secrets/
devdb.txt qadb.txt
# read secret devdb
k exec --stdin=true --tty=true devsomazapp -c devsomazapp -n somaz -- cat /vault/secrets/devdb.txt
# read secret qadb
k exec --stdin=true --tty=true devsomazapp -c devsomazapp -n somaz -- cat /vault/secrets/qadb.txt
Check the connection log.
k logs devsomazapp -c devsomazapp -n somaz
Setting User Policy
If you check the policy using Root Token on the web, you can see it all.
I can’t see anything when I connect to the user called Somaz.
Log in with the CLI to check.
vault login -method=userpass username=somaz password=<password>
vault token lookup
Create and assign policies.
# root로 로그인
vault login hvs.bOXica9b3vWqfBaiZWfASOC1
# 정책 생성
vault policy write admin - <<EOF
path "*" {
capabilities = ["create", "read", "update", "delete", "list", "sudo"]
}
EOF
vault write auth/userpass/users/somaz policies=devdb policies=admin
vault read auth/userpass/users/somaz
I can see it well. I gave you all the authority.
Comments