Vault Overview

HashiCorp Vault is the single source of truth for every credential in devhome —
vCenter/ESXi logins, VM admin passwords, ArgoCD/Rancher tokens, HAProxy certs, and
Terraform provider auth. Nothing should ever be hardcoded in a .tfvars,
.pkrvars.hcl, or script.
Official download
Vault install/downloads — always current.
Why this matters more than it might elsewhere
This repo replaced a previous one (devhome-gitops, ~2026-06-18) that had to be
abandoned outright because secrets were committed to its git history across scattered,
ad-hoc paths (devhome/vcenter, devhome/terraform/vsphere, devhome/terraform/compute,
devhome/terraform/azure, devhome/packer/windows, devhome/personal/govc, and
plaintext .auto.pkrvars.hcl/.tfvars files) — rather than rewrite that git history, the
whole working tree was copied to a fresh location with a clean history and pushed to a
new Azure DevOps repo. That relocation is why the current TrueNAS-hosted repo path
(/mnt/backup/config/devhome, \\truenas-dr\backup\config\devhome) exists in the first
place, and why "secrets in Vault, never in git" isn't a nice-to-have here — it's a
lesson already paid for once.
The consolidation that followed (~2026-06-16 to 2026-06-17) collapsed all of those
scattered paths into the small, domain-organized set below, all managed by
terraform/vault/ (one .tf file per secret). Values are supplied from
/mnt/backup/config/terraform/vault/terraform.tfvars (gitignored, TrueNAS-only) via
make tf-apply-vault. The old paths (devhome/vcenter and the rest listed above) still
technically exist in Vault but are unreferenced by any code — if you find a script or
doc pointing at one of them, it's stale, not a hint that the path is real.
Two Azure DevOps repos with the same content, only one of them live
For about two days after the relocation, the old devhome-gitops repo and the new
devhome repo both existed with byte-identical k8s/ trees but zero shared git
history — and ArgoCD's Application/ApplicationSet objects were still pointed at
the old one. Fixes pushed to devhome had silently zero effect on the live cluster
until this was caught and every repoURL (in git and live-patched directly onto
the cluster objects, since they aren't self-syncing app-of-apps) was repointed. If a
git push ever seems to have "no effect" on a live ArgoCD-managed resource, checking
argocd app get <name> for which repo it's actually synced from is a real
diagnostic step, not paranoia — see ArgoCD.
Runs on truenas-dr
Vault runs as a Docker container on truenas-dr (see
TrueNAS Services), with an unsealer sidecar container that
re-unseals it automatically after a restart — which matters, because "restart the
Vault container" is a real, sometimes-necessary fix (see
Kubernetes Auth).
KV mount layout — devhome
| Path | Contents |
|---|---|
devhome/vmware |
The big one: vsphere_server, vsphere_username, vsphere_password, esxi_host_username, esxi_host_password, esxi_license, vcsa_root_user/vcsa_root_passowrd (typo kept intentionally — matches the live field name), vm_admin_password, haproxy_cert_chain/haproxy_lb_username/haproxy_lb_password/haproxy_root_password, govc_datacenter/govc_insecure. Consumed by all 3 vsphere Terraform roots, every Packer builder, WSL's configure-personal.sh, and Ansible. |
devhome/dir_path |
truenas_base_path, kubeconfig_base_dir, secrets_base_dir, terraform_state_dir, ssh_key_dir — shared filesystem base paths used to build config/cert directory paths consistently across scripts |
devhome/azure |
arm_client_id/arm_tenant_id/arm_client_secret/arm_subscription_id, azuredevops_pat/azuredevops_org_service_url, dns_zone/resource_group (the last two were added directly to Vault but aren't wired into terraform/azure/main.tf yet — that file still hardcodes devhome-prod/devhome.cloud, a known gap) |
devhome/argocd |
argocd_server_addr, argocd_username, argocd_password |
devhome/rancher |
rancher_url, rancher_admin_password |
devhome/packer |
build_username, dsrm_password, ssh_password, plus a flat (not nested — Packer's vault() HCL function can't read nested JSON) os_metadata block of Windows image/KMS keys |
Packer's vault() function needs a literal /data/ segment
vault("devhome/data/<secret>", "<field>") — KV-v2's API path always has /data/ in
the middle, easy to forget when every other consumer's syntax hides it (Terraform's
data source, Ansible's lookup plugin, and PowerShell's Invoke-RestMethod calls all
take the mount/path separately rather than as one concatenated string).
There is no devhome/vcenter path
A couple of older scripts referenced a devhome/vcenter secret with username/
password fields that never actually existed post-reorg — the real path is
devhome/vmware with vsphere_username/vsphere_password. If a script 403s or
gets an empty {"errors":[]} response from Vault, check for this exact mistake
before assuming a permissions problem.
Reading secrets from Terraform
data.vault_kv_secret_v2 data sources pull these at plan/apply time — see
Terraform.