HashiCorp Vault

Cloud: Multi-Cloud / On-Premises
HSM Level: FIPS 140-2 Level 2 (Transit SE)
PQ Support: Possible via custom plugins

HashiCorp Vault as central secrets and PKI management for multi-cloud environments.


Architecture

flowchart TB subgraph VAULT["HASHICORP VAULT"] subgraph ENGINES["Secret Engines"] PKI[PKI Engine] KV[KV Secrets] Transit[Transit] end subgraph AUTH["Auth Methods"] K8S[Kubernetes] OIDC[OIDC] AWS[AWS IAM] AZURE[Azure] end end subgraph CONSUMERS["CONSUMERS"] EKS[AWS EKS] AKS[Azure AKS] GKE[GCP GKE] VM[VMs] end PKI --> EKS & AKS & GKE & VM K8S --> EKS & AKS & GKE AWS --> EKS AZURE --> AKS style VAULT fill:#e8f5e9 style PKI fill:#fff3e0


Installation

Docker (Development)

# Development mode (not for production!)
docker run -d --name vault \
    -p 8200:8200 \
    -e 'VAULT_DEV_ROOT_TOKEN_ID=root' \
    -e 'VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200' \
    hashicorp/vault:latest

Production (Helm)

# Helm repository
helm repo add hashicorp https://helm.releases.hashicorp.com
 
# Create values
cat > vault-values.yaml << 'EOF'
server:
  ha:
    enabled: true
    replicas: 3
    raft:
      enabled: true
  dataStorage:
    size: 10Gi
  auditStorage:
    enabled: true
    size: 10Gi
  ingress:
    enabled: true
    hosts:
      - host: vault.example.com
  extraEnvironmentVars:
    VAULT_SEAL_TYPE: awskms
    VAULT_AWSKMS_SEAL_KEY_ID: <kms-key-id>
 
injector:
  enabled: true
EOF
 
# Installation
helm install vault hashicorp/vault \
    --namespace vault \
    --create-namespace \
    -f vault-values.yaml

PKI Engine

Create Root CA

# Enable PKI engine
vault secrets enable -path=pki pki
 
# Set max TTL
vault secrets tune -max-lease-ttl=87600h pki
 
# Generate Root CA
vault write pki/root/generate/internal \
    common_name="Example Root CA" \
    issuer_name="root-2024" \
    ttl=87600h \
    key_type=ec \
    key_bits=384
 
# Configure CRL/OCSP URLs
vault write pki/config/urls \
    issuing_certificates="https://vault.example.com/v1/pki/ca" \
    crl_distribution_points="https://vault.example.com/v1/pki/crl" \
    ocsp_servers="https://vault.example.com/v1/pki/ocsp"

Create Intermediate CA

# Intermediate PKI engine
vault secrets enable -path=pki_int pki
vault secrets tune -max-lease-ttl=43800h pki_int
 
# Generate CSR
vault write -format=json pki_int/intermediate/generate/internal \
    common_name="Example Intermediate CA" \
    issuer_name="intermediate-2024" \
    key_type=ec \
    key_bits=384 \
    | jq -r '.data.csr' > intermediate.csr
 
# Sign with Root
vault write -format=json pki/root/sign-intermediate \
    csr=@intermediate.csr \
    format=pem_bundle \
    ttl=43800h \
    | jq -r '.data.certificate' > intermediate.pem
 
# Import signed certificate
vault write pki_int/intermediate/set-signed \
    certificate=@intermediate.pem

Role for Certificate Issuance

# Server certificate role
vault write pki_int/roles/server-cert \
    allowed_domains="example.com" \
    allow_subdomains=true \
    max_ttl=720h \
    key_type=ec \
    key_bits=384 \
    require_cn=false \
    allow_any_name=false
 
# Client certificate role
vault write pki_int/roles/client-cert \
    allowed_domains="example.com" \
    allow_subdomains=true \
    client_flag=true \
    server_flag=false \
    max_ttl=720h

Issue Certificate

# Server certificate
vault write pki_int/issue/server-cert \
    common_name="server.example.com" \
    alt_names="server.example.com,server" \
    ttl=720h
 
# Client certificate
vault write pki_int/issue/client-cert \
    common_name="client@example.com" \
    ttl=720h

Kubernetes Integration

Kubernetes Auth

# Enable Kubernetes auth
vault auth enable kubernetes
 
# Kubernetes config
vault write auth/kubernetes/config \
    kubernetes_host="https://kubernetes.default.svc" \
    kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
 
# Role for cert-manager
vault write auth/kubernetes/role/cert-manager \
    bound_service_account_names=cert-manager \
    bound_service_account_namespaces=cert-manager \
    policies=pki-issue \
    ttl=1h

Policy

# pki-issue.hcl
path "pki_int/issue/server-cert" {
  capabilities = ["create", "update"]
}
 
path "pki_int/sign/server-cert" {
  capabilities = ["create", "update"]
}
 
path "pki_int/roles/server-cert" {
  capabilities = ["read"]
}
vault policy write pki-issue pki-issue.hcl

Cert-Manager Vault Issuer

# vault-issuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: vault-issuer
spec:
  vault:
    path: pki_int/sign/server-cert
    server: https://vault.example.com
    caBundle: <base64-encoded-ca>
    auth:
      kubernetes:
        role: cert-manager
        mountPath: /v1/auth/kubernetes
        serviceAccountRef:
          name: cert-manager
# certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: app-tls
  namespace: production
spec:
  secretName: app-tls-secret
  issuerRef:
    name: vault-issuer
    kind: ClusterIssuer
  dnsNames:
    - app.example.com

Vault Agent Sidecar

# pod-with-vault-agent.yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-with-certs
  annotations:
    vault.hashicorp.com/agent-inject: "true"
    vault.hashicorp.com/role: "app-role"
    vault.hashicorp.com/agent-inject-secret-tls.crt: "pki_int/issue/server-cert"
    vault.hashicorp.com/agent-inject-template-tls.crt: |
      {{- with secret "pki_int/issue/server-cert" "common_name=app.example.com" -}}
      {{ .Data.certificate }}
      {{ .Data.issuing_ca }}
      {{- end }}
    vault.hashicorp.com/agent-inject-secret-tls.key: "pki_int/issue/server-cert"
    vault.hashicorp.com/agent-inject-template-tls.key: |
      {{- with secret "pki_int/issue/server-cert" "common_name=app.example.com" -}}
      {{ .Data.private_key }}
      {{- end }}
spec:
  serviceAccountName: app-sa
  containers:
    - name: app
      image: myapp:latest
      volumeMounts:
        - name: tls
          mountPath: /etc/tls
          readOnly: true

Transit Engine (Signing)

# Enable Transit engine
vault secrets enable transit
 
# Create signing key
vault write transit/keys/signing-key \
    type=ecdsa-p384
 
# Sign
vault write transit/sign/signing-key \
    input=$(echo -n "data to sign" | base64)
 
# Verify
vault write transit/verify/signing-key \
    input=$(echo -n "data to sign" | base64) \
    signature="vault:v1:..."

Audit Logging

# File audit backend
vault audit enable file file_path=/var/log/vault/audit.log
 
# Syslog backend
vault audit enable syslog tag="vault" facility="LOCAL0"
 
# Socket backend (for ELK)
vault audit enable socket address="logstash.example.com:5000" socket_type="tcp"

High Availability

# vault-config.hcl
storage "raft" {
  path = "/vault/data"
  node_id = "node1"
}
 
listener "tcp" {
  address = "0.0.0.0:8200"
  tls_cert_file = "/vault/tls/tls.crt"
  tls_key_file = "/vault/tls/tls.key"
}
 
seal "awskms" {
  region     = "eu-central-1"
  kms_key_id = "alias/vault-unseal"
}
 
api_addr = "https://vault-0.vault:8200"
cluster_addr = "https://vault-0.vault:8201"

Checklist

# Checkpoint Done
——————
1 Vault installed (HA)
2 PKI engine configured
3 Root + Intermediate CA
4 Roles defined
5 Kubernetes auth
6 Audit logging
7 Auto-unseal configured
8 Backup strategy


« <- AWS KMS | -> Operator Scenarios »


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional

Zuletzt geändert: on 2026/01/30 at 01:26 AM