From 63c243ce5134a6f04345e999b9f5ac0004f544a8 Mon Sep 17 00:00:00 2001 From: Mukul Sharma Date: Sat, 12 Sep 2026 14:23:17 +0530 Subject: [PATCH] GKE: Vault values, auto-unsealing from Cloud KMS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same chart (0.34.1) and same shape as the homelab — production mode, file storage, standalone, no HA, injector off — with one substantial difference: this Vault unseals itself. The homelab unseals with 3 of 5 Shamir keys after every restart, which was fine on an always-on VM. These nodes are spot and can be reclaimed at any hour, and a sealed Vault means every secret in the cluster is unavailable until someone notices. The trade is named rather than buried: unsealing now depends on GCP IAM rather than on people holding key shares. The seal stanza's values come from terraform output vault_seal, so Terraform and this file cannot disagree about which key is used, and no credential appears in either: the pod authenticates to KMS as its Workload Identity. That binding names exactly vault/vault, so serviceAccount.name is pinned and the GSA annotation set — miss either and Vault starts, fails to reach KMS, and stays sealed with an error that never mentions Workload Identity. Verified against the live project: the rendered seal block matches the existing key ring and key, which grant encrypt/decrypt to that service account and nothing else. Storage is 10Gi on standard-rwo. The homelab's 5Gi exists only because local-path cannot expand a bound volume; this class can. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01LEsTefWWifp4ikvhHF5s6N --- .../vault/custom-values.yaml | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 helm-overrides/gke-toolshed-prd-usc1/vault/custom-values.yaml diff --git a/helm-overrides/gke-toolshed-prd-usc1/vault/custom-values.yaml b/helm-overrides/gke-toolshed-prd-usc1/vault/custom-values.yaml new file mode 100644 index 0000000..0a75940 --- /dev/null +++ b/helm-overrides/gke-toolshed-prd-usc1/vault/custom-values.yaml @@ -0,0 +1,91 @@ +vault: + # GKE counterpart of helm-overrides/k8s-admin-prd-ase1/vault, same chart + # (0.34.1) and same shape — production mode, file storage, standalone, no + # HA — with one substantial difference: this Vault unseals itself from + # Cloud KMS instead of by hand. + # + # The homelab unseals with 3 of 5 Shamir keys after every restart. That + # was fine on an always-on VM. Here the nodes are spot and can be + # reclaimed at any hour, and a sealed Vault means every secret in the + # cluster is unavailable until a human notices. The trade, stated plainly: + # unsealing now depends on GCP IAM rather than on people holding key + # shares. + # + # This is a fresh install, not an adoption. Init is still a one-off manual + # step (`vault operator init`), and with a KMS seal it returns RECOVERY + # keys plus a root token — recovery keys cannot unseal a running Vault, + # they exist to recover or rekey it. Keep them and the root token in a + # password manager; they belong in neither Git nor Vault itself. + + injector: + enabled: false + + server: + # The Workload Identity binding Terraform created names exactly + # vault/vault — this namespace and this service account name. The + # annotation is the other half of that pair. Miss either and Vault + # starts, fails to reach KMS, and stays sealed with a permission error + # that does not mention Workload Identity at all. + serviceAccount: + create: true + name: vault + annotations: + iam.gke.io/gcp-service-account: toolshed-vault@toolshed-testing-508208.iam.gserviceaccount.com + + dataStorage: + enabled: true + # 10Gi rather than the homelab's 5Gi: that number exists only because + # local-path cannot expand a bound volume. standard-rwo can expand, so + # this is the chart default, not a constraint. + size: 10Gi + storageClass: standard-rwo + + ha: + enabled: false + + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + memory: 256Mi + + standalone: + enabled: true + # `ui = true` here AND ui.enabled below are both required — the chart + # has two separate toggles for the same thing, and setting only one + # leaves the UI 404ing (claude.md issue #10). + # + # The seal stanza's values come from terraform output vault_seal, so + # Terraform and this file cannot disagree about which key Vault + # unseals with. No credentials appear here: the pod authenticates to + # KMS as its Workload Identity, so there is no key file to mount, + # rotate, or leak. + config: | + ui = true + listener "tcp" { + address = "[::]:8200" + cluster_address = "[::]:8201" + tls_disable = "true" # lab only - enable TLS for anything beyond local testing + } + storage "file" { + path = "/vault/data" + } + seal "gcpckms" { + project = "toolshed-testing-508208" + region = "us-central1" + key_ring = "toolshed-vault" + crypto_key = "unseal" + } + + # Single host — no Tailscale here. Plain HTTP through Contour, matching + # tls_disable above. + ingress: + enabled: true + ingressClassName: contour + hosts: + - host: "vault.35.238.248.203.nip.io" + paths: [] + + ui: + enabled: true