++ wrap all vault secret values under data key for selective sops encryption

This commit is contained in:
Kochetkov S 2026-08-04 15:20:08 +03:00
parent 284b235626
commit d08b3e1771
5 changed files with 2279 additions and 2259 deletions

View File

@ -1,5 +1,19 @@
creation_rules:
- path_regex: infrastructure-secrets\.yaml$
# Точечное шифрование: только значения под буквально именованным ключом
# `data` (рекурсивно, весь его поддерево). ВСЕ секретные значения обязаны
# лежать именно под data - это структурный инвариант файла, а не
# опциональное соглашение. См. environments.<env>.vault.data.{common,
# infrastructure} и environments.<env>.secrets[].data. Несекретная
# конфигурация (enabled/kv_mount/features/applications-policy-config/
# namespaces/databases/kafka-topics и т.д.) остаётся читаемой в git-diff.
#
# ВНИМАНИЕ: если добавляешь новое секретное поле НЕ под ключ data - оно
# уйдёт в git открытым текстом молча, без ошибки. Именно так эта ветка уже
# один раз утекла (плоское дерево vault.common/vault.infrastructure без
# обёртки data). Прежде чем добавлять новый путь для секрета - убедиться,
# что он физически вложен под data, а не просто "выглядит как секрет".
encrypted_regex: "^(data)$"
# Переходный период разделения ключей по окружениям: старый общий ключ
# (все три окружения) остаётся вторым получателем, пока CI-переменная
# SOPS_AGE_KEY не переключена на новый contour-only ключ в каждой Gitea

File diff suppressed because it is too large Load Diff

View File

@ -26,11 +26,12 @@ locals {
secrets = try(local.secret_values_env.secrets, [])
# image-pull-secret (regcred) fan-out. Single source: vault.common.regcred.dockerconfigjson.
# image-pull-secret (regcred) fan-out. Single source: vault.data.common.regcred.dockerconfigjson
# (secret values live under vault.data.* - see .sops.yaml encrypted_regex).
# Rolled as a kubernetes.io/dockerconfigjson secret named `regcred` into every
# namespace flagged `image_pull_secret: true` in infrastructure.yaml. Only created
# when the source is a real docker config (guards against the CHANGE_ME placeholder).
regcred_dockerconfigjson = try(local.secret_values_env.vault.common.regcred.dockerconfigjson, "")
regcred_dockerconfigjson = try(local.secret_values_env.vault.data.common.regcred.dockerconfigjson, "")
regcred_valid = can(jsondecode(local.regcred_dockerconfigjson))
regcred_namespaces = [
for ns in try(local.infra_config.environments[local.env_name].namespaces, []) :

View File

@ -56,8 +56,11 @@ terraform {
inputs = {
vault_kv_mount = try(local.vault_config.kv_mount, "secrets")
path_prefix = try(local.vault_config.path_prefix, "vault")
common = try(local.vault_config.common, {})
infra = try(local.vault_config.infrastructure, {})
# Секретные значения обёрнуты под vault.data.* (см. .sops.yaml) - шифруется
# только этот поддерево, а не весь файл. applications ниже - конфиг policy/
# role, секретов не содержит, поэтому вне data.
common = try(local.vault_config.data.common, {})
infra = try(local.vault_config.data.infrastructure, {})
applications = try(local.vault_config.applications, {})
default_rsa_bits = try(local.vault_config.default_rsa_bits, 4096)
kubernetes_auth_backend = try(local.vault_config.kubernetes_auth_backend, "kubernetes")

View File

@ -701,7 +701,9 @@ locals {
cfg,
{
secret_path = trimspace(try(cfg.secret_path, ""))
secret_data = try(cfg.secret_data, {})
# Секретные значения обёрнуты под applications.<app>.data.secret_data
# (см. .sops.yaml encrypted_regex) - secret_path не секрет, это путь.
secret_data = try(cfg.data.secret_data, {})
read_paths = distinct(compact(concat(
[for path in try(cfg.read_paths, []) : trimspace(path)],
trimspace(try(cfg.secret_path, "")) != "" ? [trimspace(try(cfg.secret_path, ""))] : []