mirror of
https://gitlab.sarex.io/infra/terraform-contour-mirror.git
synced 2026-08-05 18:31:00 +03:00
++ fail secrets plan on incomplete depends_on instead of writing empty data
This commit is contained in:
parent
c7e04cb836
commit
12e406acad
@ -247,6 +247,47 @@ locals {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Явный контракт для типов с обязательным depends_on. Раньше отсутствующее
|
||||||
|
# или неполное depends_on тихо резолвилось через try(..., "") в несуществующий
|
||||||
|
# ключ outputs-карты, outputs_by_secret[name] становился null, и секрет молча
|
||||||
|
# создавался ПУСТЫМ (без host/port/username/password) - без единой ошибки в
|
||||||
|
# плане. Для type=yc_sa такой защиты не было вообще: null-источник просто не
|
||||||
|
# проверялся, и итоговые access_key/secret_key/service_account_id молча
|
||||||
|
# оставались пустыми строками. Здесь это - явная ошибка плана. Секреты с
|
||||||
|
# готовым статическим data (adopt/1:1) под контракт не подпадают: они не
|
||||||
|
# резолвят depends_on вообще.
|
||||||
|
secrets_contract_errors = {
|
||||||
|
for name, secret in local.secrets_map : name => (
|
||||||
|
length(try(secret.data, {})) > 0 ? "" :
|
||||||
|
secret.type == "database" || secret.type == "database_url" ? (
|
||||||
|
try(secret.depends_on.cluster, "") == "" || try(secret.depends_on.db, "") == "" || try(secret.depends_on.user, "") == ""
|
||||||
|
? "type=${secret.type} requires depends_on.cluster, depends_on.db, depends_on.user (got cluster=${try(secret.depends_on.cluster, "")}, db=${try(secret.depends_on.db, "")}, user=${try(secret.depends_on.user, "")})"
|
||||||
|
: ""
|
||||||
|
) :
|
||||||
|
secret.type == "valkey" ? (
|
||||||
|
local.valkey_dependency_keys[name].cluster == "" || local.valkey_dependency_keys[name].user == ""
|
||||||
|
? "type=valkey requires depends_on.cluster (or valkey_cluster) and depends_on.user (or valkey_user)"
|
||||||
|
: ""
|
||||||
|
) :
|
||||||
|
secret.type == "rabbitmq" ? (
|
||||||
|
try(secret.depends_on.rabbitmq_vhost, try(secret.depends_on.vhost, "")) == "" || try(secret.depends_on.rabbitmq_user, try(secret.depends_on.user, "")) == ""
|
||||||
|
? "type=rabbitmq requires depends_on.vhost (or rabbitmq_vhost) and depends_on.user (or rabbitmq_user)"
|
||||||
|
: ""
|
||||||
|
) :
|
||||||
|
secret.type == "kafka" ? (
|
||||||
|
try(coalesce(secret.depends_on.kafka_ref, secret.depends_on.cluster_ref, secret.depends_on.cluster), "") == "" || try(coalesce(secret.depends_on.kafka_user, secret.depends_on.user), "") == ""
|
||||||
|
? "type=kafka requires depends_on.kafka_ref (or cluster_ref/cluster) and depends_on.kafka_user (or user)"
|
||||||
|
: ""
|
||||||
|
) :
|
||||||
|
secret.type == "yc_sa" ? (
|
||||||
|
try(secret.depends_on.service_account, "") == ""
|
||||||
|
? "type=yc_sa requires depends_on.service_account"
|
||||||
|
: ""
|
||||||
|
) :
|
||||||
|
""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
# Если для секрета заданы явные значения (data) - используем их 1:1,
|
# Если для секрета заданы явные значения (data) - используем их 1:1,
|
||||||
# иначе собираем data из outputs/custom/constant/random как обычно.
|
# иначе собираем data из outputs/custom/constant/random как обычно.
|
||||||
secrets_data = {
|
secrets_data = {
|
||||||
@ -326,6 +367,10 @@ resource "kubernetes_secret" "with_ignore" {
|
|||||||
lifecycle {
|
lifecycle {
|
||||||
# Игнорируем data, type и metadata чтобы не было phantom updates
|
# Игнорируем data, type и metadata чтобы не было phantom updates
|
||||||
ignore_changes = [data, type, metadata, wait_for_service_account_token]
|
ignore_changes = [data, type, metadata, wait_for_service_account_token]
|
||||||
|
precondition {
|
||||||
|
condition = local.secrets_contract_errors[each.key] == ""
|
||||||
|
error_message = "Secret contract violation for ${each.key}: ${local.secrets_contract_errors[each.key]}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,6 +395,10 @@ resource "kubernetes_secret" "without_ignore" {
|
|||||||
lifecycle {
|
lifecycle {
|
||||||
# type и metadata игнорируем чтобы не было phantom updates
|
# type и metadata игнорируем чтобы не было phantom updates
|
||||||
ignore_changes = [type, metadata, wait_for_service_account_token]
|
ignore_changes = [type, metadata, wait_for_service_account_token]
|
||||||
|
precondition {
|
||||||
|
condition = local.secrets_contract_errors[each.key] == ""
|
||||||
|
error_message = "Secret contract violation for ${each.key}: ${local.secrets_contract_errors[each.key]}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,4 +412,11 @@ resource "vault_kv_secret_v2" "this" {
|
|||||||
data_json = jsonencode(merge(each.value.data, {
|
data_json = jsonencode(merge(each.value.data, {
|
||||||
for key, config in each.value.random_keys : key => random_password.secrets["${each.key}:${key}"].result
|
for key, config in each.value.random_keys : key => random_password.secrets["${each.key}:${key}"].result
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
precondition {
|
||||||
|
condition = local.secrets_contract_errors[each.key] == ""
|
||||||
|
error_message = "Secret contract violation for ${each.key}: ${local.secrets_contract_errors[each.key]}"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user