DEV Community

Cover image for Deploying and Managing HashiCorp Vault in Kubernetes with HA and Raft Storage
Durrell Gemuh
Durrell Gemuh

Posted on

Deploying and Managing HashiCorp Vault in Kubernetes with HA and Raft Storage

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 
Enter fullscreen mode Exit fullscreen mode

Add the HashiCorp Helm repo and update:

helm repo add hashicorp https://helm.releases.hashicorp.com helm repo update 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

Install Vault:

helm install vault hashicorp/vault -n vault -f values.yaml 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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. 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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"] 
Enter fullscreen mode Exit fullscreen mode
  • 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 
Enter fullscreen mode Exit fullscreen mode

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> 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

Troubleshooting Common Issues

ClusterRoleBinding Already Exists

  • Delete conflicting ClusterRoleBinding before reinstalling Helm chart:
kubectl delete clusterrolebinding vault-server-binding 
Enter fullscreen mode Exit fullscreen mode

Helm Upgrade Errors ("no deployed releases")

  • Uninstall previous release from default namespace:
helm uninstall vault -n default 
Enter fullscreen mode Exit fullscreen mode
  • Then install again in the proper namespace.

Pods Not Unsealing or Ready

  • Check pod logs for errors:
kubectl logs vault-1 -n vault 
Enter fullscreen mode Exit fullscreen mode
  • Verify PVCs are bound and healthy:
kubectl get pvc -n vault 
Enter fullscreen mode Exit fullscreen mode
  • 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 
Enter fullscreen mode Exit fullscreen mode
  • 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 
Enter fullscreen mode Exit fullscreen mode

Removing Corrupted Raft Node

  • Remove node from cluster:
kubectl exec -it vault-0 -n vault -- vault operator raft remove-peer <node-id> 
Enter fullscreen mode Exit fullscreen mode
  • 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.

Up Next: Vault Web UI - Accessing and viewing vault on UI

Top comments (0)