Pod - Hashicorp Vault #18
Labels
No labels
blocked
bug
duplicate
effort
high
effort
low
effort
medium
effort
minimal
enhancement
help wanted
invalid
pr
feedback
pr
reviewing
question
status
backlog
status
document
status
done
status
implement
status
pending
status
planning
status
reviewing
waiting
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
tepichord/milner#18
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
worker-largeworker nodevault/README.mdunder a# SetupsectionNaina:
Overview
Migrate Vault out of podman-compose into the official
hashicorp/vaultHelm chart as a single-replica StatefulSet in a newvaultnamespace on worker-large. The nginx Tailscale-TLS proxy survives as a pod sidecar, and Vault's data moves to a dedicated 20 GiB qcow2 volume that is physically stored underdata_root_pathand reaches the pod via a Talos user volume mounted at/var/mnt/vault. Three Terraform roots change (control-plane NodePort range, worker data disk, newvault/root driving the Helm release); every manual step is documented undervault/README.md→# Setup.Technical Approach
talos-imagespool, so its backing file lands at${data_root_path}/images/talos-kvm/milner-worker-1-vault.qcow2)34./var/mnt/vaultis auto-propagated into the kubelet so pods can hostPath it)56.vault/Terraform root, driving the cluster with credentials parsed from the CP kubeconfig output (same remote-state pattern asworker/)89.Also here: two
kubernetes_secret_v1(certs read from gitignored paths interraform.auto.tfvars), a ConfigMap for nginx,helm_release.vault, and the nginx Service.server.standalone.config(chart PVC disabled — data on the hostPath volume; TLS and mlock settings carried over)1011.server.extraContainers(same-pod proxy to127.0.0.1:8200, Tailscale cert secret) and expose it with its own NodePort Service1213.vault/README.md→# Setup(issue criterion 2) and decommission the podman stack once the in-cluster Vault is verified:Implementation Details
control-plane/main.tf,control-plane/tests/worker/main.tflibvirt_volume.vault_data(vdb) +UserVolumeConfigpatch inconfig_patchesworker/tests/plan.tftest.hclworker/cleanup.shdestroy14vault/(new root)main.tf,values.yaml,terraform.tfvars,.gitignore,tests/plan.tftest.hcl+ fixturevault/README.md# Setup(criterion 2)tests/test_static.py,tests/test_terraform.pyvault/and drophc-vaultentries; add vaultterraform testrun1516hc-vault/values.yaml+ nginx ConfigMap)README.md,AGENTS.md,PLAN.mdhc-vault/→vault/Dependencies and constraints:
hashicorp/kubernetes+hashicorp/helm(repo first use); no flake change —helm_releaseremoves thehelmCLI dependency1718.disable_mlock = trueand the arm64 multi-arch official image1920212223.vaultnamespace gets the PSAprivilegedlabel; the chart's own securityContext (runAsNonRoot, drop ALL) stays baseline-compliant2425.-replace='libvirt_domain.worker') keeps the vault volume; only a fullterraform destroyremoves it2627.kubeconfigoutput; secretfile()sources resolve to fixture files during plan tests (never real certs)2829.Out-of-scope notes (discovered, not requested):
woodpecker/values.yamlalready assumes alocal-pathStorageClass, so that lands with issue #19, not this one30.Acceptance Criteria
vault/root applies cleanly: StatefulSetvault-0runs on worker-large in thevaultnamespace with the officialhashicorp/vaultimage + nginx sidecar, and reachesReadyafter unseal./var/mnt/vault, whose backing qcow2 lives underdata_root_path, and survives both a pod delete andterraform apply -replace='libvirt_domain.worker'.https://<tailnet-name>:8443serves the Vault UI through the nginx sidecar and direct:8200responds, via NodePorts 8443/8200 (range widened to 8080–32767).vault/README.mdcontains a# Setupsection covering cert prep/import, apply order, init/unseal, host reachability, and legacy-stack decommission.vault/plan tests, and updated pytest lint/fmt lists (terraform fmt, yamllint onvalues.yaml).hc-vault/podman-compose stack removed from the repo and all doc references repointed after in-cluster cutover is verified.Testing Plan
terraform -chdir=control-plane test— assert the apiserver patch setsservice-node-port-range = "8080-32767".terraform -chdir=worker test— vault volume is 20 GiB qcow2 namedmilner-worker-1-vault.qcow2, domain has a vdb virtio disk, and aconfig_patchesentry yaml-decodes toUserVolumeConfig name=vault.terraform -chdir=vault test(mocked helm/kubernetes + CP fixture) — namespace carries the PSAprivilegedlabel;helm_release.vaulthas chartvault, namespacevault, and values markers (nodeSelector,tlsDisable=false,dataStorage.enabled=false); nginx Service NodePorts are 8443/8080.python -m pytest tests/ -v— fmt coversvault/, yamllint passesvault/values.yaml, no stalehc-vaultlints.# Setup, not automated): init/unseal; UI login over tailnet :8443; sealed→unsealed survives a worker reboot; cert renewal path unchanged from today.Related Issues/PRs
data_root_path, kubeconfig output)removeddoctrine applied here)# Setupmanual steps)Research Findings
hashicorp/vaultHelm chart is the recommended install path; it always renders a StatefulSet (standalone = 1 replica,filestorage,OnDeleteupgrades), configured viaserver.standalone.config.hashicorp/vault:1.15.4is EOL (1.15 line ended 2024-10); official images are multi-arch (arm64 OK), anddisable_mlock = trueremains the right setting in containers since image 2.0.2 removedIPC_LOCK.baselineon every namespace exceptkube-system, andbaselineforbids hostPath volumes — thevaultnamespace must be labeledenforce=privileged; a PVC + local-path provisioner would avoid it but adds a cluster component.UserVolumeConfig, Talos ≥ 1.10) partition a dedicated disk and auto-propagate/var/mnt/<name>into the kubelet for hostPath/subPath use (schema verified against the Talos v1.11 docs).--service-node-port-rangeextraArg is a reconcile-only control-plane change./vault/userconfig/…, referenced bylistener tcptls_*_file) matches the mkcert material the repo already owns, so certs are imported, not regenerated.Pre-Mortem
The new Talos user volume never surfaces
/var/mnt/vaultto the kubelet, stranding the Vault pod — the plan itself flags thediskSelectorCEL for verification "against Talos v1.11 docs at implement time", and a subtle mismatch means Talos rejects the worker machine config at apply or the volume isn't auto-propagated, leavingvault-0Pending/CrashLooping behind a hostPath mount that never appears. Because the offline plan tests only mock the machine-config patch, this only shows up as a live-cluster failure where recovering risks reformatting or replacing the wrong disk.Chart/image drift or a config regression breaks the real
helm_releaseapply that mocked tests can't see — the plan pins chart 0.34.x / image 2.0.4 at research time with an explicit "re-verify at implement time" caveat, and if the live chart schema differs (dataStorage.enabled=false,extraContainersshape) or the tag is gone, the apply fails only against the cluster. A portedstandalone.configHCL error (wrongstorage/listenerstanza for the 2.x line) then crash-loops the pod, and each retry round-trips a full apply cycle on the shared worker.Cutover mishap loses existing Vault data or the tailnet endpoint — the file backend is not copyable between instances, so re-seeding via API is the only data path; if unseal keys/root token are mishandled or the old podman DNAT rules die before the NodePort retarget is verified, the live UI becomes unreachable and prior secrets are unrecoverable.