apiVersion: apps/v1 kind: StatefulSet metadata: name: vault namespace: vault spec: serviceName: vault-internal replicas: 3 selector: matchLabels: app.kubernetes.io/name: vault template: metadata: labels: app.kubernetes.io/name: vault spec: serviceAccountName: vault # Allows k8s auth for autounsealing terminationGracePeriodSeconds: 10 affinity: # 1. Pin the pods strictly to K3s server nodes # nodeAffinity: # requiredDuringSchedulingIgnoredDuringExecution: # nodeSelectorTerms: # - matchExpressions: # - key: node-role.kubernetes.io/control-plane # operator: Exists # 2. Force those pods onto different physical server nodes podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app.kubernetes.io/name operator: In values: ["vault"] topologyKey: "kubernetes.io/hostname" securityContext: runAsUser: 100 runAsGroup: 1000 fsGroup: 1000 initContainers: - name: fix-raft-permissions image: busybox:latest command: ["sh", "-c", "chown -R 100:1000 /vault/data && chmod -R 700 /vault/data"] volumeMounts: - name: data mountPath: /vault/data securityContext: runAsUser: 0 privileged: true - name: fetch-transit-token image: hashicorp/vault:latest command: ["sh", "-c"] args: - | set -e K8S_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) TRANSIT_TOKEN=$(vault write -field=token auth/kubernetes/login \ role=vault-unsealer \ jwt=$K8S_TOKEN) sed "s/REPLACE_WITH_TOKEN/$TRANSIT_TOKEN/" /etc/vault/extraconfig-from-values.hcl > /vault/runtime/vault.hcl securityContext: allowPrivilegeEscalation: false capabilities: add: ["IPC_LOCK"] env: - name: VAULT_ADDR value: "http://vault-keykeeper.vault.svc.cluster.local:80" volumeMounts: - name: config mountPath: /etc/vault - name: config-runtime mountPath: /vault/runtime containers: - name: vault image: hashicorp/vault:latest args: ["server", "-config=/vault/runtime/vault.hcl"] securityContext: allowPrivilegeEscalation: false capabilities: add: ["IPC_LOCK"] env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: VAULT_API_ADDR value: "http://$(POD_NAME).vault-internal.vault.svc.cluster.local:8200" - name: VAULT_CLUSTER_ADDR value: "https://$(POD_NAME).vault-internal.vault.svc.cluster.local:8201" - name: SKIP_SETCAP value: "true" - name: VAULT_ADDR value: "http://127.0.0.1:8200" - name: VAULT_K8S_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: VAULT_K8S_POD_NAME valueFrom: fieldRef: fieldPath: metadata.name ports: - containerPort: 8200 name: http - containerPort: 8201 name: https-internal volumeMounts: - name: config mountPath: /etc/vault - name: data mountPath: /vault/data - name: config-runtime mountPath: /vault/runtime livenessProbe: httpGet: path: /v1/sys/health?standbyok=true&sealedok=true port: 8200 scheme: HTTP initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 3 timeoutSeconds: 5 readinessProbe: httpGet: path: /v1/sys/health?standbyok=true port: 8200 initialDelaySeconds: 10 periodSeconds: 5 volumes: - name: config configMap: name: vault-config - name: config-runtime emptyDir: {} volumeClaimTemplates: - metadata: name: data spec: accessModes: [ "ReadWriteOnce" ] storageClassName: longhorn resources: requests: storage: 1Gi