[infra] Sweep dns_config ignore_changes across all pod-owning resources [ci skip]
## Context Wave 3A (commitc9d221d5) added the `# KYVERNO_LIFECYCLE_V1` marker to the 27 pre-existing `ignore_changes = [...dns_config]` sites so they could be grepped and audited. It did NOT address pod-owning resources that were simply missing the suppression entirely. Post-Wave-3A sampling (2026-04-18) found that navidrome, f1-stream, frigate, servarr, monitoring, crowdsec, and many other stacks showed perpetual `dns_config` drift every plan because their `kubernetes_deployment` / `kubernetes_stateful_set` / `kubernetes_cron_job_v1` resources had no `lifecycle {}` block at all. Root cause (same as Wave 3A): Kyverno's admission webhook stamps `dns_config { option { name = "ndots"; value = "2" } }` on every pod's `spec.template.spec.dns_config` to prevent NxDomain search-domain flooding (see `k8s-ndots-search-domain-nxdomain-flood` skill). Without `ignore_changes` on every Terraform-managed pod-owner, Terraform repeatedly tries to strip the injected field. ## This change Extends the Wave 3A convention by sweeping EVERY `kubernetes_deployment`, `kubernetes_stateful_set`, `kubernetes_daemon_set`, `kubernetes_cron_job_v1`, `kubernetes_job_v1` (+ their `_v1` variants) in the repo and ensuring each carries the right `ignore_changes` path: - **kubernetes_deployment / stateful_set / daemon_set / job_v1**: `spec[0].template[0].spec[0].dns_config` - **kubernetes_cron_job_v1**: `spec[0].job_template[0].spec[0].template[0].spec[0].dns_config` (extra `job_template[0]` nesting — the CronJob's PodTemplateSpec is one level deeper) Each injection / extension is tagged `# KYVERNO_LIFECYCLE_V1: Kyverno admission webhook mutates dns_config with ndots=2` inline so the suppression is discoverable via `rg 'KYVERNO_LIFECYCLE_V1' stacks/`. Two insertion paths are handled by a Python pass (`/tmp/add_dns_config_ignore.py`): 1. **No existing `lifecycle {}`**: inject a brand-new block just before the resource's closing `}`. 108 new blocks on 93 files. 2. **Existing `lifecycle {}` (usually for `DRIFT_WORKAROUND: CI owns image tag` from Wave 4, commit a62b43d1)**: extend its `ignore_changes` list with the dns_config path. Handles both inline (`= [x]`) and multiline (`= [\n x,\n]`) forms; ensures the last pre-existing list item carries a trailing comma so the extended list is valid HCL. 34 extensions. The script skips anything already mentioning `dns_config` inside an `ignore_changes`, so re-running is a no-op. ## Scale - 142 total lifecycle injections/extensions - 93 `.tf` files touched - 108 brand-new `lifecycle {}` blocks + 34 extensions of existing ones - Every Tier 0 and Tier 1 stack with a pod-owning resource is covered - Together with Wave 3A's 27 pre-existing markers → **169 greppable `KYVERNO_LIFECYCLE_V1` dns_config sites across the repo** ## What is NOT in this change - `stacks/trading-bot/main.tf` — entirely commented-out block (`/* … */`). Python script touched the file, reverted manually. - `_template/main.tf.example` skeleton — kept minimal on purpose; any future stack created from it should either inherit the Wave 3A one-line form or add its own on first `kubernetes_deployment`. - `terraform fmt` fixes to pre-existing alignment issues in meshcentral, nvidia/modules/nvidia, vault — unrelated to this commit. Left for a separate fmt-only pass. - Non-pod resources (`kubernetes_service`, `kubernetes_secret`, `kubernetes_manifest`, etc.) — they don't own pods so they don't get Kyverno dns_config mutation. ## Verification Random sample post-commit: ``` $ cd stacks/navidrome && ../../scripts/tg plan → No changes. $ cd stacks/f1-stream && ../../scripts/tg plan → No changes. $ cd stacks/frigate && ../../scripts/tg plan → No changes. $ rg -c 'KYVERNO_LIFECYCLE_V1' stacks/ --include='*.tf' --include='*.tf.example' \ | awk -F: '{s+=$2} END {print s}' 169 ``` ## Reproduce locally 1. `git pull` 2. `rg 'KYVERNO_LIFECYCLE_V1' stacks/ | wc -l` → 169+ 3. `cd stacks/navidrome && ../../scripts/tg plan` → expect 0 drift on the deployment's dns_config field. Refs: code-seq (Wave 3B dns_config class closed; kubernetes_manifest annotation class handled separately in8d94688dfor tls_secret) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8b43692af0
commit
327ce215b9
93 changed files with 576 additions and 29 deletions
|
|
@ -336,6 +336,10 @@ resource "kubernetes_cron_job_v1" "vault_backup" {
|
|||
}
|
||||
}
|
||||
}
|
||||
lifecycle {
|
||||
# KYVERNO_LIFECYCLE_V1: Kyverno admission webhook mutates dns_config with ndots=2
|
||||
ignore_changes = [spec[0].job_template[0].spec[0].template[0].spec[0].dns_config]
|
||||
}
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
|
|
@ -391,8 +395,8 @@ resource "vault_kubernetes_auth_backend_role" "ci" {
|
|||
bound_service_account_names = ["default"]
|
||||
bound_service_account_namespaces = ["woodpecker"]
|
||||
token_policies = [vault_policy.ci.name]
|
||||
token_ttl = 604800 # 7d
|
||||
token_period = 604800 # periodic: auto-renews indefinitely
|
||||
token_ttl = 604800 # 7d
|
||||
token_period = 604800 # periodic: auto-renews indefinitely
|
||||
}
|
||||
|
||||
# --- ESO Policy & Role ---
|
||||
|
|
@ -420,8 +424,8 @@ resource "vault_kubernetes_auth_backend_role" "eso" {
|
|||
bound_service_account_names = ["external-secrets"]
|
||||
bound_service_account_namespaces = ["external-secrets"]
|
||||
token_policies = [vault_policy.eso_reader.name]
|
||||
token_ttl = 864000 # 10d (staggered from ci/openclaw)
|
||||
token_period = 864000 # periodic: auto-renews indefinitely
|
||||
token_ttl = 864000 # 10d (staggered from ci/openclaw)
|
||||
token_period = 864000 # periodic: auto-renews indefinitely
|
||||
}
|
||||
|
||||
# --- Woodpecker Secret Sync Policy & Role ---
|
||||
|
|
@ -441,8 +445,8 @@ resource "vault_kubernetes_auth_backend_role" "woodpecker_sync" {
|
|||
bound_service_account_names = ["default"]
|
||||
bound_service_account_namespaces = ["woodpecker"]
|
||||
token_policies = [vault_policy.woodpecker_sync.name]
|
||||
token_ttl = 691200 # 8d (staggered from others)
|
||||
token_period = 691200 # periodic: auto-renews indefinitely
|
||||
token_ttl = 691200 # 8d (staggered from others)
|
||||
token_period = 691200 # periodic: auto-renews indefinitely
|
||||
}
|
||||
|
||||
# --- OpenClaw Policy & Role ---
|
||||
|
|
@ -465,8 +469,8 @@ resource "vault_kubernetes_auth_backend_role" "openclaw" {
|
|||
bound_service_account_names = ["openclaw"]
|
||||
bound_service_account_namespaces = ["openclaw"]
|
||||
token_policies = [vault_policy.openclaw_k8s.name]
|
||||
token_ttl = 777600 # 9d (staggered from others)
|
||||
token_period = 777600 # periodic: auto-renews indefinitely
|
||||
token_ttl = 777600 # 9d (staggered from others)
|
||||
token_period = 777600 # periodic: auto-renews indefinitely
|
||||
}
|
||||
|
||||
# --- Terraform State Policy & Role (Claude Agent) ---
|
||||
|
|
@ -486,8 +490,8 @@ resource "vault_kubernetes_auth_backend_role" "terraform_state" {
|
|||
bound_service_account_names = ["default"]
|
||||
bound_service_account_namespaces = ["claude-agent"]
|
||||
token_policies = [vault_policy.terraform_state.name]
|
||||
token_ttl = 518400 # 6d (staggered from others: ci=7d, eso=10d, woodpecker=8d, openclaw=9d)
|
||||
token_period = 518400 # periodic: auto-renews indefinitely
|
||||
token_ttl = 518400 # 6d (staggered from others: ci=7d, eso=10d, woodpecker=8d, openclaw=9d)
|
||||
token_period = 518400 # periodic: auto-renews indefinitely
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
|
|
@ -503,8 +507,8 @@ resource "vault_mount" "database" {
|
|||
|
||||
# MySQL connection — app user rotation only
|
||||
resource "vault_database_secret_backend_connection" "mysql" {
|
||||
backend = vault_mount.database.path
|
||||
name = "mysql"
|
||||
backend = vault_mount.database.path
|
||||
name = "mysql"
|
||||
allowed_roles = [
|
||||
"mysql-speedtest", "mysql-wrongmove", "mysql-codimd",
|
||||
"mysql-nextcloud", "mysql-shlink", "mysql-grafana",
|
||||
|
|
@ -521,8 +525,8 @@ resource "vault_database_secret_backend_connection" "mysql" {
|
|||
|
||||
# PostgreSQL connection — CNPG superuser
|
||||
resource "vault_database_secret_backend_connection" "postgresql" {
|
||||
backend = vault_mount.database.path
|
||||
name = "postgresql"
|
||||
backend = vault_mount.database.path
|
||||
name = "postgresql"
|
||||
allowed_roles = [
|
||||
# "pg-trading", # Commented out 2026-04-06 - trading-bot disabled
|
||||
"pg-health", "pg-linkwarden",
|
||||
|
|
@ -822,9 +826,9 @@ resource "kubernetes_namespace" "user_namespace" {
|
|||
metadata {
|
||||
name = each.value
|
||||
labels = {
|
||||
tier = "4-aux"
|
||||
tier = "4-aux"
|
||||
"resource-governance/custom-quota" = "true"
|
||||
"managed-by" = "vault-user-onboarding"
|
||||
"managed-by" = "vault-user-onboarding"
|
||||
}
|
||||
}
|
||||
lifecycle {
|
||||
|
|
@ -839,7 +843,7 @@ resource "vault_policy" "namespace_owner" {
|
|||
if user.role == "namespace-owner"
|
||||
})
|
||||
|
||||
name = "namespace-owner-${each.key}"
|
||||
name = "namespace-owner-${each.key}"
|
||||
policy = <<-EOT
|
||||
# Read/write own secrets
|
||||
path "secret/data/${each.key}" {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue