From eef4c2cd497c171308a16fd03e0f02727681d318 Mon Sep 17 00:00:00 2001 From: Ben Vincent Date: Sat, 23 May 2026 18:22:25 +1000 Subject: [PATCH] feat(vault): deploy HashiCorp Vault 2.0.1 with raft HA (5 replicas) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit StatefulSet with templated PVC (cephrbd-fast-delete, 10Gi), headless service for raft cluster communication, HTTPS gateway (443→8200), and kubernetes provider retry_join for automatic cluster formation. --- apps/base/vault/gateway.yaml | 31 +++++ apps/base/vault/httproute.yaml | 23 ++++ apps/base/vault/kustomization.yaml | 21 ++++ apps/base/vault/namespace.yaml | 5 + apps/base/vault/resources/vault.hcl | 19 +++ apps/base/vault/role.yaml | 16 +++ apps/base/vault/rolebinding.yaml | 17 +++ apps/base/vault/service.yaml | 23 ++++ apps/base/vault/service_headless.yaml | 24 ++++ apps/base/vault/serviceaccount.yaml | 9 ++ apps/base/vault/statefulset.yaml | 110 ++++++++++++++++++ .../overlays/au-syd1/vault/kustomization.yaml | 8 ++ argocd/applicationsets/platform.yaml | 1 + 13 files changed, 307 insertions(+) create mode 100644 apps/base/vault/gateway.yaml create mode 100644 apps/base/vault/httproute.yaml create mode 100644 apps/base/vault/kustomization.yaml create mode 100644 apps/base/vault/namespace.yaml create mode 100644 apps/base/vault/resources/vault.hcl create mode 100644 apps/base/vault/role.yaml create mode 100644 apps/base/vault/rolebinding.yaml create mode 100644 apps/base/vault/service.yaml create mode 100644 apps/base/vault/service_headless.yaml create mode 100644 apps/base/vault/serviceaccount.yaml create mode 100644 apps/base/vault/statefulset.yaml create mode 100644 apps/overlays/au-syd1/vault/kustomization.yaml diff --git a/apps/base/vault/gateway.yaml b/apps/base/vault/gateway.yaml new file mode 100644 index 0000000..6895ff6 --- /dev/null +++ b/apps/base/vault/gateway.yaml @@ -0,0 +1,31 @@ +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: vault + namespace: vault + labels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault + traefik.io/instance: internal + annotations: + cert-manager.io/cluster-issuer: vault-issuer + cert-manager.io/common-name: vault.k8s.syd1.au.unkin.net + cert-manager.io/private-key-size: "4096" + external-dns.alpha.kubernetes.io/hostname: vault.k8s.syd1.au.unkin.net + external-dns.alpha.kubernetes.io/target: 198.18.200.4 +spec: + gatewayClassName: traefik-internal + listeners: + - name: https + port: 443 + protocol: HTTPS + hostname: vault.k8s.syd1.au.unkin.net + allowedRoutes: + namespaces: + from: Same + tls: + mode: Terminate + certificateRefs: + - kind: Secret + name: vault-tls diff --git a/apps/base/vault/httproute.yaml b/apps/base/vault/httproute.yaml new file mode 100644 index 0000000..2622095 --- /dev/null +++ b/apps/base/vault/httproute.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: vault + namespace: vault + labels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault +spec: + hostnames: + - vault.k8s.syd1.au.unkin.net + parentRefs: + - name: vault + sectionName: https + rules: + - backendRefs: + - name: vault + port: 8200 + matches: + - path: + type: PathPrefix + value: / diff --git a/apps/base/vault/kustomization.yaml b/apps/base/vault/kustomization.yaml new file mode 100644 index 0000000..19dd192 --- /dev/null +++ b/apps/base/vault/kustomization.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - namespace.yaml + - serviceaccount.yaml + - role.yaml + - rolebinding.yaml + - statefulset.yaml + - service.yaml + - service_headless.yaml + - gateway.yaml + - httproute.yaml + +configMapGenerator: + - name: vault-config + files: + - resources/vault.hcl + options: + disableNameSuffixHash: true diff --git a/apps/base/vault/namespace.yaml b/apps/base/vault/namespace.yaml new file mode 100644 index 0000000..33be07a --- /dev/null +++ b/apps/base/vault/namespace.yaml @@ -0,0 +1,5 @@ +--- +apiVersion: v1 +kind: Namespace +metadata: + name: vault diff --git a/apps/base/vault/resources/vault.hcl b/apps/base/vault/resources/vault.hcl new file mode 100644 index 0000000..7612cf2 --- /dev/null +++ b/apps/base/vault/resources/vault.hcl @@ -0,0 +1,19 @@ +ui = true + +listener "tcp" { + address = "0.0.0.0:8200" + cluster_address = "0.0.0.0:8201" + tls_disable = "true" +} + +storage "raft" { + path = "/vault/data" + + retry_join { + auto_join = "provider=k8s label_selector=\"app.kubernetes.io/name=vault\" namespace=\"vault\"" + auto_join_scheme = "http" + auto_join_port = 8200 + } +} + +service_registration "kubernetes" {} diff --git a/apps/base/vault/role.yaml b/apps/base/vault/role.yaml new file mode 100644 index 0000000..5a24a84 --- /dev/null +++ b/apps/base/vault/role.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: vault + namespace: vault + labels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["get", "list", "watch"] + - apiGroups: [""] + resources: ["pods"] + verbs: ["patch", "update"] diff --git a/apps/base/vault/rolebinding.yaml b/apps/base/vault/rolebinding.yaml new file mode 100644 index 0000000..1a67374 --- /dev/null +++ b/apps/base/vault/rolebinding.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: vault + namespace: vault + labels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: vault +subjects: + - kind: ServiceAccount + name: vault + namespace: vault diff --git a/apps/base/vault/service.yaml b/apps/base/vault/service.yaml new file mode 100644 index 0000000..ad7d519 --- /dev/null +++ b/apps/base/vault/service.yaml @@ -0,0 +1,23 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: vault + namespace: vault + labels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault +spec: + type: ClusterIP + ports: + - name: api + port: 8200 + targetPort: api + protocol: TCP + - name: cluster + port: 8201 + targetPort: cluster + protocol: TCP + selector: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault diff --git a/apps/base/vault/service_headless.yaml b/apps/base/vault/service_headless.yaml new file mode 100644 index 0000000..9e0daa6 --- /dev/null +++ b/apps/base/vault/service_headless.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: vault-internal + namespace: vault + labels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault +spec: + clusterIP: None + publishNotReadyAddresses: true + ports: + - name: api + port: 8200 + targetPort: api + protocol: TCP + - name: cluster + port: 8201 + targetPort: cluster + protocol: TCP + selector: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault diff --git a/apps/base/vault/serviceaccount.yaml b/apps/base/vault/serviceaccount.yaml new file mode 100644 index 0000000..2263fca --- /dev/null +++ b/apps/base/vault/serviceaccount.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: vault + namespace: vault + labels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault diff --git a/apps/base/vault/statefulset.yaml b/apps/base/vault/statefulset.yaml new file mode 100644 index 0000000..2b19aa0 --- /dev/null +++ b/apps/base/vault/statefulset.yaml @@ -0,0 +1,110 @@ +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: vault + namespace: vault + labels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault + app.kubernetes.io/version: 2.0.1 +spec: + serviceName: vault-internal + replicas: 5 + selector: + matchLabels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault + template: + metadata: + labels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault + app.kubernetes.io/version: 2.0.1 + spec: + serviceAccountName: vault + terminationGracePeriodSeconds: 10 + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + app.kubernetes.io/name: vault + containers: + - name: vault + image: hashicorp/vault:2.0.1 + command: + - vault + - server + - -config=/vault/config + ports: + - name: api + containerPort: 8200 + protocol: TCP + - name: cluster + containerPort: 8201 + protocol: TCP + env: + - name: POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: VAULT_ADDR + value: "http://127.0.0.1:8200" + - name: VAULT_API_ADDR + value: "http://$(POD_IP):8200" + - name: VAULT_CLUSTER_ADDR + value: "http://$(POD_IP):8201" + - name: VAULT_RAFT_NODE_ID + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: SKIP_SETCAP + value: "true" + readinessProbe: + httpGet: + path: /v1/sys/health?standbyok=true&sealedok=true&uninitok=true + port: 8200 + scheme: HTTP + initialDelaySeconds: 5 + periodSeconds: 10 + failureThreshold: 3 + livenessProbe: + httpGet: + path: /v1/sys/health?standbyok=true&sealedok=true&uninitok=true + port: 8200 + scheme: HTTP + initialDelaySeconds: 60 + periodSeconds: 30 + failureThreshold: 3 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 1000m + memory: 2Gi + volumeMounts: + - name: data + mountPath: /vault/data + - name: config + mountPath: /vault/config + volumes: + - name: config + configMap: + name: vault-config + volumeClaimTemplates: + - metadata: + name: data + labels: + app.kubernetes.io/name: vault + app.kubernetes.io/instance: vault + spec: + accessModes: ["ReadWriteOnce"] + storageClassName: cephrbd-fast-delete + resources: + requests: + storage: 10Gi diff --git a/apps/overlays/au-syd1/vault/kustomization.yaml b/apps/overlays/au-syd1/vault/kustomization.yaml new file mode 100644 index 0000000..6347401 --- /dev/null +++ b/apps/overlays/au-syd1/vault/kustomization.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: vault + +resources: + - ../../../base/vault diff --git a/argocd/applicationsets/platform.yaml b/argocd/applicationsets/platform.yaml index 218d5ea..63be86a 100644 --- a/argocd/applicationsets/platform.yaml +++ b/argocd/applicationsets/platform.yaml @@ -27,6 +27,7 @@ spec: - path: apps/overlays/*/reposync - path: apps/overlays/*/traefik-system - path: apps/overlays/*/vm-system + - path: apps/overlays/*/vault - path: apps/overlays/*/vso-system - path: apps/overlays/*/woodpecker template: