Secrets & Vault Paths¶
Reference for secrets management and Vault path organization.
Vault Path Structure¶
secret/
└── fzymgc-house/
├── cluster/ # Kubernetes service secrets
│ ├── authentik # Authentik admin credentials
│ ├── argocd/ # ArgoCD configuration
│ ├── grafana # Grafana admin/OIDC
│ ├── vault/ # Vault configuration
│ ├── temporal/ # Temporal worker secrets
│ ├── discord/ # Discord bot credentials
│ ├── workers/ # Temporal workflow secrets (HMAC keys, etc.)
│ ├── mealie # Mealie secrets
│ ├── nats # NATS NKey credentials
│ ├── mosquitto # Mosquitto MQTT credentials
│ ├── github # GitHub tokens
│ ├── cloudflared/ # Tunnel credentials
│ ├── tailscale/ # Tailscale operator OAuth
│ ├── alloy # Alloy external collector auth
│ ├── merlin # Merlin (OpenClaw) gateway credentials
│ ├── dolt # Dolt SQL server credentials
│ └── postgres/ # Database credentials
│ └── users/ # Per-app DB users
├── infrastructure/ # Infrastructure credentials
│ ├── cloudflare/ # Cloudflare API tokens
│ ├── hcp/ # HCP Terraform credentials
│ └── bmc/ # BMC credentials per node
└── applications/ # Application-specific secrets
Cluster Secrets¶
| Path | Purpose | Keys |
|---|---|---|
secret/fzymgc-house/cluster/authentik |
Authentik admin | terraform_token, secret_key, bootstrap_password, email_host, email_port, email_username, email_password, email_use_tls, email_from |
secret/fzymgc-house/cluster/argocd |
ArgoCD config | admin_password, github_token, oidc_secret, webhook.github.secret |
secret/fzymgc-house/cluster/grafana |
Grafana secrets | admin_password, oidc_client_id, oidc_client_secret |
secret/fzymgc-house/cluster/vault/* |
Vault config | oidc_client_id, oidc_client_secret |
secret/fzymgc-house/cluster/temporal/* |
Temporal worker secrets | Various per-workflow |
secret/fzymgc-house/cluster/temporal/github |
GitHub App for repo cloning | app_id, installation_id, private_key |
secret/fzymgc-house/cluster/workers/drift-detection |
Drift detection workflow | discord-webhook-hmac-key |
secret/fzymgc-house/cluster/discord/bot |
Discord bot | token |
secret/fzymgc-house/cluster/mealie |
Mealie config | oidc_client_id, oidc_client_secret |
secret/fzymgc-house/cluster/nats |
NATS NKey auth | operator_jwt, operator_public, sys_account_seed, sys_account_public, sys_account_jwt, services_account_seed, services_account_public, services_account_jwt, iot_account_seed, iot_account_public, iot_account_jwt |
secret/fzymgc-house/cluster/mosquitto |
Mosquitto MQTT auth | passwd (pre-hashed output from mosquitto_passwd), bridge_username (any non-empty), bridge_password (IOT user bearer JWT for NATS MQTT) |
secret/fzymgc-house/cluster/github |
GitHub integration | app_id, app_private_key, webhook_secret |
secret/fzymgc-house/cluster/cloudflared/* |
Tunnel creds | tunnel_token, tunnel_id |
secret/fzymgc-house/cluster/tailscale/oauth |
Tailscale operator OAuth | clientId, clientSecret |
secret/fzymgc-house/cluster/alloy |
Alloy external collector auth | external_token |
secret/fzymgc-house/cluster/merlin |
Merlin (OpenClaw) gateway | gateway-token, claude-ai-session-key, gh-token, synthetic-api-key, openai-api-key, elevenlabs-api-key, openrouter-api-key |
secret/fzymgc-house/cluster/dolt |
Dolt SQL server credentials | root_password, agent_user, agent_password, beads_user, beads_password |
secret/fzymgc-house/cluster/postgres/users/* |
DB users | username, password |
Infrastructure Secrets¶
| Path | Purpose | Keys |
|---|---|---|
secret/fzymgc-house/infrastructure/cloudflare/bootstrap-token |
Terraform token | token |
secret/fzymgc-house/infrastructure/cloudflare/discord-webhook |
Notifications | url |
secret/fzymgc-house/infrastructure/cloudflare/hcp-terraform-hmac |
Webhook auth | secret |
secret/fzymgc-house/infrastructure/cloudflare/hcp-terraform-worker |
Worker auth | token |
secret/fzymgc-house/infrastructure/hcp |
HCP credentials | client_id, client_secret |
secret/fzymgc-house/infrastructure/bmc/* |
Node BMC creds | username, password |
secret/fzymgc-house/infrastructure/router/kopia-r2 |
Router Kopia backup to R2 | username (R2 access key), password (R2 secret key), repo_password (Kopia encryption) |
secret/fzymgc-house/infrastructure/router/dhcpv6 |
Router DHCPv6 DUID | duid (colon-separated hex bytes for IPv6 prefix persistence) |
Vault Policies¶
Policy to Secret Path Mapping¶
| Policy | Paths | Consumers |
|---|---|---|
external-secrets-operator |
secret/data/* (read) |
External Secrets Operator |
fzymgc-cluster-secret-reader |
secret/data/* (read) |
General cluster read access |
arc-runners |
secret/data/fzymgc-house/cluster/github |
GitHub Actions runners |
temporal-worker |
secret/data/fzymgc-house/cluster/temporal/*, secret/data/fzymgc-house/cluster/discord/*, secret/data/fzymgc-house/cluster/github/*, secret/data/fzymgc-house/cluster/cloudflare/r2/*, secret/data/fzymgc-house/cluster/workers/* |
Temporal workers |
temporal-worker-terraform |
secret/data/fzymgc-house/cluster/hcp-terraform, secret/data/fzymgc-house/cluster/discord/cluster-notifications-app, secret/data/fzymgc-house/cluster/workers/drift-detection, secret/data/fzymgc-house/cluster/temporal/github |
Terraform drift detection & GuardedApply workflow |
terraform-router-hosts-admin |
fzymgc-house/v1/ica1/v1/issue/router-hosts-client, fzymgc-house/v1/ica1/v1/cert/ca, fzymgc-house/v1/ica1/v1/ca_chain, sys/mounts/fzymgc-house/v1/ica1/v1 |
GuardedApplyWorkflow PKI cert renewal |
terraform-hcp-terraform-local |
secret/data/fzymgc-house/infrastructure/cloudflare/hcp-terraform-worker, secret/data/fzymgc-house/infrastructure/cloudflare/hcp-terraform-hmac, secret/data/fzymgc-house/infrastructure/pki/fzymgc-ica1-ca |
GuardedApplyWorkflow hcp-terraform module |
alloy-agent |
secret/data/fzymgc-house/cluster/alloy |
Firewalla Alloy collector |
cert-manager |
pki/fzymgc-house/* |
cert-manager PKI |
mealie |
secret/data/fzymgc-house/cluster/mealie, secret/data/fzymgc-house/cluster/postgres/users/main-mealie |
Mealie app |
nats |
secret/data/fzymgc-house/cluster/nats |
NATS server |
merlin |
secret/data/fzymgc-house/cluster/merlin |
Merlin (OpenClaw) gateway service |
github-actions |
secret/data/fzymgc-house/cluster/github |
CI/CD workflows |
hcp-terraform |
Multiple cluster paths | Terraform workspaces |
infrastructure-developer |
secret/data/fzymgc-house/infrastructure/*, secret/data/fzymgc-house/* (read) |
Human operators |
admin |
secret/* (full) |
Administrators |
Auth Methods¶
| Method | Mount | Purpose |
|---|---|---|
| Kubernetes | kubernetes/ |
Service account auth |
| OIDC | oidc/ |
Human SSO via Authentik |
| AppRole | approle/ |
Automation/CI |
| JWT | jwt/ |
HCP Terraform |
Kubernetes Integration¶
ClusterSecretStore¶
apiVersion: external-secrets.io/v1
kind: ClusterSecretStore
metadata:
name: vault
spec:
provider:
vault:
server: "https://vault-internal.vault:8200"
path: "secret"
version: "v2"
auth:
kubernetes:
mountPath: "kubernetes"
role: "external-secrets"
ExternalSecret Example¶
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: grafana-admin
namespace: grafana
spec:
secretStoreRef:
name: vault
kind: ClusterSecretStore
target:
name: grafana-admin-secret
data:
- secretKey: admin-password
remoteRef:
key: fzymgc-house/cluster/grafana
property: admin_password
Adding New Secrets¶
1. Create Secret in Vault¶
# Login to Vault
export VAULT_ADDR=https://vault.fzymgc.house
vault login -method=oidc
# Create secret
vault kv put secret/fzymgc-house/cluster/new-service \
api_key="value" \
secret_key="value"
# Verify
vault kv get secret/fzymgc-house/cluster/new-service
2. Create ExternalSecret¶
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: new-service-secrets
namespace: new-service
spec:
secretStoreRef:
name: vault
kind: ClusterSecretStore
target:
name: new-service-secrets
data:
- secretKey: API_KEY
remoteRef:
key: fzymgc-house/cluster/new-service
property: api_key
- secretKey: SECRET_KEY
remoteRef:
key: fzymgc-house/cluster/new-service
property: secret_key
3. Update Policy (if new path)¶
If using a new path pattern, update the relevant policy in tf/vault/:
resource "vault_policy" "new-service" {
name = "new-service"
policy = <<EOT
# Allow service to read its secrets from Vault
path "secret/data/fzymgc-house/cluster/new-service" {
capabilities = ["read"]
}
# Required for ExternalSecrets to verify secret existence
path "secret/metadata/fzymgc-house/cluster/new-service" {
capabilities = ["read"]
}
EOT
}
Secret Naming Conventions¶
| Type | Pattern | Example |
|---|---|---|
| Service secrets | secret/fzymgc-house/cluster/<service> |
secret/fzymgc-house/cluster/grafana |
| Sub-service secrets | secret/fzymgc-house/cluster/<service>/<component> |
secret/fzymgc-house/cluster/argocd/github |
| Database users | secret/fzymgc-house/cluster/postgres/users/<db>-<user> |
secret/fzymgc-house/cluster/postgres/users/main-mealie |
| Infrastructure | secret/fzymgc-house/infrastructure/<provider> |
secret/fzymgc-house/infrastructure/cloudflare |
| Per-node secrets | secret/fzymgc-house/infrastructure/<type>/<node> |
secret/fzymgc-house/infrastructure/bmc/tpi-alpha-1 |
Rotation Procedures¶
Manual Rotation¶
# Update secret value
vault kv put secret/fzymgc-house/cluster/service key=new-value
# Restart dependent pods
kubectl rollout restart deployment/service -n namespace
Automated Rotation¶
ExternalSecrets refreshes secrets based on refreshInterval:
Troubleshooting¶
Verify Secret Access¶
# Check Vault path exists
vault kv get secret/fzymgc-house/cluster/service
# Check ExternalSecret status
kubectl get externalsecret -n namespace
kubectl describe externalsecret name -n namespace
# Check synced Kubernetes secret
kubectl get secret name -n namespace -o yaml
Common Issues¶
| Issue | Cause | Solution |
|---|---|---|
SecretSyncedError |
Wrong path or missing permissions | Verify Vault path and policy |
| Secret not updating | refreshInterval not elapsed |
Wait or trigger manual refresh |
| Permission denied | Missing policy binding | Update Kubernetes auth role |
See Vault Operations for detailed operational procedures.