Vault is a powerful secrets management tool. Running Vault on Kubernetes in HA mode with Raft backend provides resilience and scalability for secure secrets storage. This guide covers: installing Vault, setting up namespaces, deploying via Helm, joining Vault nodes, unsealing, and troubleshooting common issues.
Prerequisites
- Kubernetes cluster accessible with
kubectl
- Helm 3 installed
- Sufficient permissions to create namespaces and PVs
- Basic familiarity with Vault concepts and Kubernetes
Step 1: Setting Up Namespace and Helm Repo
Create a namespace for Vault to isolate it:
kubectl create namespace vault
Add the HashiCorp Helm repo and update:
helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
Step 2: Installing Vault with Helm in HA Mode
Create a values.yaml
for Vault HA using Raft storage (Integrated Storage):
injector:
enabled: false
server:
image:
repository: "hashicorp/vault"
tag: "1.9.0"
# Overrides the default Image Pull Policy
pullPolicy: IfNotPresent
# Configure the Update Strategy Type for the StatefulSet
updateStrategyType: "OnDelete"
resources:
requests:
memory: 256Mi
cpu: 250m
limits:
memory: 256Mi
cpu: 250m
ha:
enabled: true
replicas: 3
raft:
enabled: true
config: |
ui = true
listener "tcp" {
tls_disable = 1
address = "[::]:8200"
cluster_address = "[::]:8201"
}
storage "raft" {
path = "/vault/data"
}
service_registration "kubernetes" {}
dataStorage:
enabled: true
size: 500Mi
Install Vault:
helm install vault hashicorp/vault -n vault -f values.yaml
Verify pods:
$ kubectl get pods -n vault
NAME READY STATUS RESTARTS
vault-0 0/1 Running 0
vault-1 0/1 Running 0
vault-2 0/1 Running 0
Step 3: Joining Vault Nodes and Initializing Cluster
- Only the first Vault pod (vault-0) is initialized once.
- Initialize Vault on
vault-0
:
kubectl exec -it vault-0 -n vault -- vault operator init -key-shares=5 -key-threshold=3
Recovery Key 1: FKjt5wkzN5bUBIuR52KrPP1c2Il/f7RZdn5E+ipfNF8s
Recovery Key 2: FCzUyduESPyavh6QtqWZpdnUDKa3bEEpBHbX3NgTrCiU
Recovery Key 3: Tf7FVEpj5tdJLqQqNw/Jt0OytRI5FAZYig/yafSVz3Xg
Recovery Key 4: duLpa/6IozTOR0mkO7sp0CwmnI+1DsC6d2+oZG/A1CIZ
Recovery Key 5: pyVFs/rRFEk9rSn57Ru+KeuAQzW6eurl3j0/pS/JRpXD
Initial Root Token: s.PMOJxNxZYgvXzby5YZr9p3J1
Vault initialized with 5 key shares and a key threshold of 3. Please securely
distribute the key shares printed above. When the Vault is re-sealed,
restarted, or stopped, you must supply at least 3 of these keys to unseal it
before it can start servicing requests.
Vault does not store the generated master key. Without at least 3 keys to
reconstruct the master key, Vault will remain permanently sealed!
It is possible to generate new unseal keys, provided you have a quorum of
existing unseal keys shares. See "vault operator rekey" for more information.
Now, we see the Vault unsealer in action:
$ kubectl exec -it vault-0 -n vault -- vault operator unseal <unseal_key_1>
$ kubectl exec -it vault-0 -n vault -- vault operator unseal <unseal_key_2>
$ kubectl exec -it vault-0 -n vault -- vault operator unseal <unseal_key_3>
$ kubectl get pods -n vault
NAME READY STATUS RESTARTS
vault-0 1/1 Running 0
vault-1 0/1 Running 0
vault-2 0/1 Running 0
However, our replica vault-1 and vault-2 are still not ready. They are follower pods of the leader vault-0. In order to make vault-0 visible, we need to login using our Initial Root Token.
$ kubectl exec -it vault-0 -- vault login s.d0LAlSnAerb4a7d6ibkfxrZy
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.
Key Value
--- -----
token s.d0LAlSnAerb4a7d6ibkfxrZy
token_accessor hJEFibLTbUP4sgA8X4tMBqZ8
token_duration ∞
token_renewable false
token_policies ["root"]
identity_policies []
policies ["root"]
- Other pods (vault-1, vault-2) must join the Raft cluster. Next, let’s join vault-1 and vault-2 to Vault-0 to make the Vault setup Highly available by running commands as shown below:
$ kubectl exec -it vault-1 -n vault -- vault operator raft join http://vault-0.vault-internal:8200
Key Value
--- -----
Joined true
$ kubectl exec -it vault-2 -n vault -- vault operator raft join http://vault-0.vault-internal:8200
Key Value
--- -----
Joined true
Save unseal keys securely.
Step 4: Unsealing Vault Pods
Unseal all Vault pods (vault-0, vault-1, vault-2) manually with the unseal keys:
kubectl exec -it vault-1 -n vault -- vault operator unseal <unseal_key_1>
kubectl exec -it vault-1 -n vault -- vault operator unseal <unseal_key_2>
kubectl exec -it vault-1 -n vault -- vault operator unseal <unseal_key_3>
kubectl exec -it vault-2 -n vault -- vault operator unseal <unseal_key_1>
kubectl exec -it vault-2 -n vault -- vault operator unseal <unseal_key_2>
kubectl exec -it vault-2 -n vault -- vault operator unseal <unseal_key_3>
Let’s check the pod status and this time you would be able to see them in running as well as Ready mode:
$ kubectl get pods -n vault
NAME READY STATUS RESTARTS
vault-0 1/1 Running 0
vault-1 1/1 Running 0
vault-2 1/1 Running 0
The last but important step is to verify whether the HA setup is correct or not, is by running the below command against each Vault pod and making sure that the value of HA Enabled parameters is true.
$ kubectl exec -it -n vault vault-0 -- vault status
Key Value
--- -----
Recovery Seal Type shamir
Initialized true
Sealed false
Total Recovery Shares 5
Threshold 3
Version 1.9.0
Storage Type raft
Cluster Name vault-cluster-30882e80
Cluster ID 1afbe13a-e951-482d-266b-e31693d17e20
HA Enabled true
HA Cluster https://vault-0.vault-internal:8201
HA Mode active
Active Since 2022-01-19T04:39:37.586622342Z
Raft Committed Index 61
Raft Applied Index 61
$ kubectl exec -it -n vault vault-1 -- vault status
Key Value
--- -----
…
HA Enabled true
HA Cluster https://vault-0.vault-internal:8201
HA Mode standby
Active Node Address http://10.244.0.17:8200
Raft Committed Index 61
Raft Applied Index 61
$ kubectl exec -it -n vault vault-2 -- vault status
Key Value
--- -----
HA Enabled true
HA Cluster https://vault-0.vault-internal:8201
HA Mode standby
Active Node Address http://10.244.0.17:8200
Raft Committed Index 61
Raft Applied Index 61
Troubleshooting Common Issues
ClusterRoleBinding Already Exists
- Delete conflicting ClusterRoleBinding before reinstalling Helm chart:
kubectl delete clusterrolebinding vault-server-binding
Helm Upgrade Errors ("no deployed releases")
- Uninstall previous release from default namespace:
helm uninstall vault -n default
- Then install again in the proper namespace.
Pods Not Unsealing or Ready
- Check pod logs for errors:
kubectl logs vault-1 -n vault
- Verify PVCs are bound and healthy:
kubectl get pvc -n vault
- If corrupted PVC, delete PVC and pod, then rejoin:
kubectl delete pvc data-vault-1 -n vault
kubectl delete pod vault-1 -n vault
kubectl exec -it vault-1 -n vault -- vault operator raft join http://vault-0.vault-internal:8200
- Unseal vault-1 after join with the same unseal keys.
PVC Stuck in Terminating
- Remove finalizers to force delete:
kubectl patch pvc data-vault-1 -n vault -p '{"metadata":{"finalizers":[]}}' --type=merge
Removing Corrupted Raft Node
- Remove node from cluster:
kubectl exec -it vault-0 -n vault -- vault operator raft remove-peer <node-id>
- Delete PVC and pod, then re-join as new.
Conclusion
Deploying Vault in Kubernetes with HA and Raft backend provides secure secret storage with scalability. Proper initialization, joining, and unsealing procedures are critical. Troubleshooting involves managing PVC health, pod status, and cluster raft membership carefully.
Top comments (0)