cebaf44db3
Pods 1 and 2 can't unseal because port 8201 (cluster port) only opens after barrier initialization, but the barrier key transfer requires 8201 to be reachable — deadlock. Running single-node on pod 0 so vault.neuralplatform.ai reliably routes to the active, unsealed instance.
176 lines
6.0 KiB
YAML
176 lines
6.0 KiB
YAML
apiVersion: argoproj.io/v1alpha1
|
|
kind: Application
|
|
metadata:
|
|
name: vault-helm-gke
|
|
namespace: argocd
|
|
annotations:
|
|
# Deploys the Vault Helm chart to the GKE cluster via Legion Argo CD.
|
|
# The destination.server must be updated after `terraform apply`:
|
|
# terraform -chdir=servers/gcp output -raw gke_cluster_endpoint
|
|
spec:
|
|
project: default
|
|
source:
|
|
repoURL: https://helm.releases.hashicorp.com
|
|
chart: vault
|
|
targetRevision: "0.29.1"
|
|
helm:
|
|
values: |
|
|
global:
|
|
enabled: true
|
|
|
|
injector:
|
|
enabled: false
|
|
|
|
ui:
|
|
enabled: true
|
|
|
|
server:
|
|
image:
|
|
repository: hashicorp/vault
|
|
tag: "1.19.2"
|
|
|
|
# Workload Identity — Vault pod k8s SA impersonates vault-unseal GCP SA
|
|
# for KMS auto-unseal. Binding is in servers/gcp/gke.tf.
|
|
serviceAccount:
|
|
create: true
|
|
name: vault
|
|
annotations:
|
|
iam.gke.io/gcp-service-account: vault-unseal@neuron-785695.iam.gserviceaccount.com
|
|
|
|
# GKE Autopilot: no privileged containers. Vault doesn't need privilege.
|
|
# Request IPC_LOCK so Vault can lock memory (prevents secrets swap).
|
|
securityContext:
|
|
capabilities:
|
|
add:
|
|
- IPC_LOCK
|
|
|
|
# Single replica for now — raft standby unsealing requires the barrier
|
|
# key to be shared over port 8201 (cluster port), but 8201 only opens
|
|
# after unsealing (deadlock). Running solo on pod 0 until we resolve
|
|
# the standby bootstrap path. Scale back to 3 once fixed.
|
|
ha:
|
|
enabled: true
|
|
replicas: 1
|
|
raft:
|
|
enabled: true
|
|
setNodeId: true
|
|
config: |
|
|
ui = true
|
|
|
|
listener "tcp" {
|
|
tls_disable = 1
|
|
address = "[::]:8200"
|
|
cluster_address = "[::]:8201"
|
|
}
|
|
|
|
storage "raft" {
|
|
path = "/vault/data"
|
|
|
|
retry_join {
|
|
leader_api_addr = "http://vault-helm-gke-0.vault-helm-gke-internal:8200"
|
|
}
|
|
retry_join {
|
|
leader_api_addr = "http://vault-helm-gke-1.vault-helm-gke-internal:8200"
|
|
}
|
|
retry_join {
|
|
leader_api_addr = "http://vault-helm-gke-2.vault-helm-gke-internal:8200"
|
|
}
|
|
}
|
|
|
|
seal "gcpckms" {
|
|
project = "neuron-785695"
|
|
region = "global"
|
|
key_ring = "vault"
|
|
crypto_key = "vault-unseal"
|
|
}
|
|
|
|
telemetry {
|
|
prometheus_retention_time = "30s"
|
|
disable_hostname = false
|
|
}
|
|
|
|
# Spread pods across GKE zones
|
|
topologySpreadConstraints:
|
|
- maxSkew: 1
|
|
topologyKey: topology.kubernetes.io/zone
|
|
whenUnsatisfiable: ScheduleAnyway
|
|
labelSelector:
|
|
matchLabels:
|
|
app.kubernetes.io/name: vault
|
|
component: server
|
|
|
|
# 10Gi SSD per pod — premium-rwo = pd-ssd on GKE Autopilot
|
|
dataStorage:
|
|
enabled: true
|
|
size: 10Gi
|
|
storageClass: standard-rwo
|
|
accessMode: ReadWriteOnce
|
|
|
|
# Annotations on the pod template — bumping rollme triggers a
|
|
# StatefulSet rolling restart (pods 2→1→0) to pick up the
|
|
# corrected raft retry_join addresses.
|
|
podAnnotations:
|
|
rollme: "2026-05-05-raft-join-fix"
|
|
|
|
readinessProbe:
|
|
enabled: true
|
|
# standbyok=true: standby pods pass (they serve reads).
|
|
# sealedok removed: sealed/uninit pods fail readiness so they
|
|
# leave the service endpoints and stop receiving external traffic.
|
|
path: "/v1/sys/health?standbyok=true"
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 5
|
|
failureThreshold: 3
|
|
|
|
livenessProbe:
|
|
enabled: true
|
|
# Liveness keeps sealedok=true so sealed pods aren't killed —
|
|
# they need time to join raft and auto-unseal.
|
|
path: "/v1/sys/health?standbyok=true&sealedok=true&uninitcode=200"
|
|
initialDelaySeconds: 60
|
|
periodSeconds: 10
|
|
failureThreshold: 3
|
|
|
|
# GKE Autopilot requires resource requests on all containers
|
|
resources:
|
|
requests:
|
|
memory: 256Mi
|
|
cpu: 500m
|
|
limits:
|
|
memory: 512Mi
|
|
cpu: 1000m
|
|
|
|
service:
|
|
enabled: true
|
|
type: ClusterIP
|
|
port: 8200
|
|
targetPort: 8200
|
|
annotations:
|
|
# Container-native NEG for GCP Global HTTPS LB backend cutover.
|
|
# GKE will create a zonal NEG named k8s1-<hash>-vault-vault-helm-gke-8200-<hash>
|
|
# in each zone where Vault pods are scheduled.
|
|
# After this syncs, list NEGs:
|
|
# gcloud compute network-endpoint-groups list --filter="name~vault" --project neuron-785695
|
|
# Then reference them in servers/gcp/vault-gke-lb.tf.
|
|
cloud.google.com/neg: '{"exposed_ports":{"8200":{}}}'
|
|
|
|
# Ingress disabled — Vault is exposed via GCP HTTPS LB.
|
|
# After migration, update the existing LB backend (vault-nodes.tf)
|
|
# to target a GKE NEG instead of the GCE instance groups.
|
|
# See: https://cloud.google.com/kubernetes-engine/docs/how-to/standalone-neg
|
|
ingress:
|
|
enabled: false
|
|
|
|
destination:
|
|
# Replace GKE_CLUSTER_ENDPOINT after `terraform apply`:
|
|
# terraform -chdir=servers/gcp output -raw gke_cluster_endpoint
|
|
server: https://34.63.89.52
|
|
namespace: vault
|
|
syncPolicy:
|
|
automated:
|
|
prune: true
|
|
selfHeal: true
|
|
syncOptions:
|
|
- CreateNamespace=true
|
|
- ServerSideApply=true
|