HashiCorp Vault on Production-ready Kubernetes: Complete Architecture Guide

HashiCorp Vault on Production-ready Kubernetes: Complete Architecture Guide

10 September 2025

Kilian Niemegeerts

You’re running Kubernetes in production. Secrets are everywhere – database passwords, API keys, certificates. You can’t commit them to Git, but your GitOps pipeline needs them. Meanwhile, your HashiCorp Vault instance goes down because it’s fighting for resources with your application pods during traffic spikes.

We built a multi-cluster Kubernetes architecture on AWS that solves these problems. Critical infrastructure runs separately,  secrets stay out of Git and everything deploys automatically.

This is part 1 of our 6-part series documenting the implementation.

HashiCorp Vault Multi-Cluster Kubernetes Architecture

Our production-ready Vault infrastructure on Kubernetes splits into two EKS clusters:

  • Application Cluster: Frontend, backend, databases, Istio service mesh
  • Tooling Cluster: HashiCorp Vault, GitLab Runner, External Secrets Operator, FluxCD

Why split them? Because mixing critical infrastructure with applications creates problems.

Why Separate Clusters for HashiCorp Vault

Different Scaling Needs

Applications scale by adding or removing pods based on traffic. Vault doesn’t. It needs consistent resources and high availability. Technically, Kubernetes gives you tools to isolate workloads within a single cluster, using node pools, resource limits, taints, and affinity rules. So yes, you can avoid resource competition in a shared cluster.

But in practice, it’s just easier to manage scaling separately. Separate clusters mean simpler setup and less room for mistakes when both workloads behave differently.

Update Cycles Don’t Match

Application deployments happen continuously. Vault upgrades need planning and testing. In the same cluster, you can update Vault separately from your apps  but not the cluster itself. If you want to update the Kubernetes version, everything in that cluster is affected. Separate clusters let us upgrade Vault independently. For example: we update the Vault cluster on Tuesday without blocking Thursday’s feature release in the app cluster.

Clear Security Boundaries

With one cluster, RBAC policies become complex – separating developers from infrastructure tools is hard. Two clusters mean different IAM roles, different policies, straightforward security.

Infrastructure Stays Up

If an application goes down, Vault shouldn’t go with it. In the same cluster, they share the same fate when the cluster itself has issues. With separate clusters, a crash in production doesn’t impact our secrets management. 

Terraform Infrastructure for Vault on Kubernetes

Manual infrastructure creates drift between environments in production Kubernetes. You deploy to dev, it works. You deploy to production three weeks later – different configs, different versions, different results. We need everything automated, versioned, and repeatable.That’s where Terraform comes in.

Our Terraform modules cover 80% of the most common Vault use cases without making things overly complex.

 

modules/
├── vpc/        # Networks per cluster
├── iam/        # Roles and policies  
├── kms/        # Vault auto-unseal keys
├── efs/        # Vault storage
└── eks/        # Cluster configs

Each cluster gets its own configuration that uses these modules with different parameters.

Secret Management Patterns in Kubernetes

Kubernetes secrets have a fundamental problem: GitOps means everything in Git, but secrets in Git mean security risks. HashiCorp Vault solves this, but introduces new questions: How do pods get secrets from Vault?

We use different patterns for different needs:

Static Secrets: External Secrets Operator

API keys and config values that rarely change use ESO. It syncs from Vault to Kubernetes Secrets without storing values in Git.

Dynamic Credentials: Database Engine

Vault creates PostgreSQL users on-demand with 1-hour lifetimes:

 

CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'

There are no shared passwords and no rotation tickets.

Vault Agent vs Secrets Operator vs CSI Provider

When you have HashiCorp Vault running, you still need to get those secrets into your applications. HashiCorp offers three approaches, each with trade-offs:

Vault Agent Injector: Adds a sidecar container that authenticates with Vault and writes secrets to a shared volume. Perfect for dynamic secrets that need automatic renewal.

Vault Secrets Operator: Creates native Kubernetes Secrets from Vault data. Great for GitOps but can’t handle dynamic credentials.

CSI Provider: Mounts secrets as volumes during pod startup. Newer approach with good flexibility.

We chose Vault Agent for dynamic database credentials because it handles lease renewal automatically – critical when credentials expire every hour.

Kubernetes Production Security with Vault

With secrets managed by Vault and infrastructure automated, we still needed to secure the runtime. Two critical questions:

  • How do services communicate securely within the cluster?
  • How do engineers access Vault without exposing it publicly?

Istio Service Mesh for Vault Security

In traditional Kubernetes, any pod can talk to any pod. That’s a security nightmare. We implemented Istio service mesh where every connection must be:

  • Encrypted (automatic mTLS)
  • Authenticated (service identity)
  • Authorized (explicit policies)

Example from our HashiCorp Vault Kubernetes setup, only the assets service can talk to ActiveMQ:

 

apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: allow-assets-to-activemq
spec:
  selector:
    matchLabels:
      app: activemq
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/app/sa/assets-sa"]

Securing Vault Access in Production

Vault contains all secrets – it must never be publicly accessible. Our solution:

  • Internal Load Balancer: No public IP exists
  • Private DNS: Clean URL via vault.tooling.internal
  • VPN Access: Engineers connect through VPN when needed

This means Vault is invisible to the internet but accessible where needed.

GitOps Deployment with FluxCD 

Infrastructure is automated with Terraform. But how do applications deploy to our Kubernetes clusters? That’s where GitOps comes in.

FluxCD watches our Git repositories and automatically deploys changes to both clusters. Update a container image? Commit to Git. Change a configuration? Commit to Git. No manual kubectl commands, no confusion about what’s deployed where.

GitLab Runner with Podman in Kubernetes

Building containers needs special attention in production-ready Kubernetes. Docker requires privileged mode – a security risk. We chose Podman for rootless builds, deployed via GitLab Runner in the tooling cluster. Even the runner registration token comes from Vault.

Getting Started with HashiCorp Vault on Kubernetes

All code from this production architecture is available in our GitHub repository:

  • Complete Terraform modules
  • Working Vault configurations
  • Bootstrap scripts and fixes
  • GitOps manifests

Need help implementing HashiCorp Vault in your Kubernetes environment? Our team has hands-on experience with production deployments. Contact FlowFactor to discuss your infrastructure challenges.

No Comments

Sorry, the comment form is closed at this time.