mirror of
https://gitlab.sarex.io/infra/terraform-contour-mirror.git
synced 2026-08-05 18:31:00 +03:00
362 lines
14 KiB
HCL
362 lines
14 KiB
HCL
|
||
|
||
locals {
|
||
# Маппинг наших типов на Kubernetes типы
|
||
k8s_secret_type_map = {
|
||
"dockerconfigjson" = "kubernetes.io/dockerconfigjson"
|
||
"database" = "Opaque"
|
||
"database_url" = "Opaque"
|
||
"s3" = "Opaque"
|
||
"valkey" = "Opaque"
|
||
"yc_sa" = "Opaque"
|
||
"rabbitmq" = "Opaque"
|
||
"kafka" = "Opaque"
|
||
"opaque" = "Opaque"
|
||
}
|
||
|
||
default_yc_sa_key_names = {
|
||
access_key = "access_key"
|
||
secret_key = "secret_key"
|
||
service_account_id = "service_account_id"
|
||
}
|
||
|
||
secrets_map = {
|
||
for secret in var.secrets : "${secret.namespace}/${secret.name}" => secret
|
||
}
|
||
|
||
random_keys_flat = merge([
|
||
for secret_name, secret in local.secrets_map : {
|
||
for key, config in try(secret.random_keys, {}) : "${secret_name}:${key}" => {
|
||
secret_name = secret_name
|
||
key = key
|
||
length = try(config.length, 32)
|
||
special = try(config.special, false)
|
||
}
|
||
}
|
||
]...)
|
||
|
||
database_outputs_by_secret = {
|
||
for name, secret in local.secrets_map : name => try(
|
||
var.database_outputs_map["${try(secret.depends_on.cluster, "")}:${try(secret.depends_on.db, "")}:${try(secret.depends_on.user, "")}"],
|
||
null
|
||
)
|
||
}
|
||
|
||
valkey_dependency_keys = {
|
||
for name, secret in local.secrets_map : name => {
|
||
cluster = try(secret.depends_on.valkey_cluster, "") != "" ? try(secret.depends_on.valkey_cluster, "") : try(secret.depends_on.cluster, "")
|
||
user = try(secret.depends_on.valkey_user, "") != "" ? try(secret.depends_on.valkey_user, "") : try(secret.depends_on.user, "")
|
||
}
|
||
}
|
||
|
||
valkey_outputs_by_secret = {
|
||
for name, secret in local.secrets_map : name => try(
|
||
var.valkey_outputs_map["${local.valkey_dependency_keys[name].cluster}:${local.valkey_dependency_keys[name].user}"],
|
||
null
|
||
)
|
||
}
|
||
|
||
rabbitmq_outputs_by_secret = {
|
||
for name, secret in local.secrets_map : name => try(
|
||
var.rabbitmq_outputs_map[
|
||
format(
|
||
"%s:%s:%s",
|
||
try(secret.depends_on.rabbitmq_ref, "default"),
|
||
try(secret.depends_on.rabbitmq_vhost, try(secret.depends_on.vhost, "")),
|
||
try(secret.depends_on.rabbitmq_user, try(secret.depends_on.user, ""))
|
||
)
|
||
],
|
||
null
|
||
)
|
||
}
|
||
|
||
kafka_outputs_by_secret = {
|
||
for name, secret in local.secrets_map : name => try(
|
||
var.kafka_outputs_map[
|
||
format(
|
||
"%s:%s",
|
||
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), "")
|
||
)
|
||
],
|
||
null
|
||
)
|
||
}
|
||
|
||
rabbitmq_default_credentials_by_secret = {
|
||
for name, secret in local.secrets_map : name => local.rabbitmq_outputs_by_secret[name] == null ? {} : {
|
||
host = local.rabbitmq_outputs_by_secret[name].host
|
||
hostname = "${local.rabbitmq_outputs_by_secret[name].host}:${local.rabbitmq_outputs_by_secret[name].port}"
|
||
port = local.rabbitmq_outputs_by_secret[name].port
|
||
vhost = local.rabbitmq_outputs_by_secret[name].vhost
|
||
user = local.rabbitmq_outputs_by_secret[name].username
|
||
username = local.rabbitmq_outputs_by_secret[name].username
|
||
password = local.rabbitmq_outputs_by_secret[name].password
|
||
uri = local.rabbitmq_outputs_by_secret[name].uri
|
||
management_endpoint = local.rabbitmq_outputs_by_secret[name].management_endpoint
|
||
}
|
||
if secret.type == "rabbitmq"
|
||
}
|
||
|
||
rabbitmq_credentials_by_secret = {
|
||
for name, secret in local.secrets_map : name => length(try(secret.credential_keys, {})) == 0 ? local.rabbitmq_default_credentials_by_secret[name] : {
|
||
for key, source in try(secret.credential_keys, {}) : key => try(local.rabbitmq_default_credentials_by_secret[name][source], "")
|
||
}
|
||
if secret.type == "rabbitmq" && local.rabbitmq_outputs_by_secret[name] != null
|
||
}
|
||
|
||
kafka_default_credentials_by_secret = {
|
||
for name, secret in local.secrets_map : name => local.kafka_outputs_by_secret[name] == null ? {} : {
|
||
host = local.kafka_outputs_by_secret[name].host
|
||
hostname = local.kafka_outputs_by_secret[name].hostname
|
||
port = local.kafka_outputs_by_secret[name].port
|
||
username = local.kafka_outputs_by_secret[name].username
|
||
user = local.kafka_outputs_by_secret[name].username
|
||
password = local.kafka_outputs_by_secret[name].password
|
||
sasl_mechanism = local.kafka_outputs_by_secret[name].sasl_mechanism
|
||
security_protocol = local.kafka_outputs_by_secret[name].security_protocol
|
||
bootstrap_server = local.kafka_outputs_by_secret[name].bootstrap_server
|
||
bootstrap_servers = local.kafka_outputs_by_secret[name].bootstrap_servers
|
||
bootstrap_servers_json = local.kafka_outputs_by_secret[name].bootstrap_servers_json
|
||
}
|
||
if secret.type == "kafka"
|
||
}
|
||
|
||
kafka_credentials_by_secret = {
|
||
for name, secret in local.secrets_map : name => length(try(secret.credential_keys, {})) == 0 ? local.kafka_default_credentials_by_secret[name] : {
|
||
for key, source in try(secret.credential_keys, {}) : key => try(local.kafka_default_credentials_by_secret[name][source], "")
|
||
}
|
||
if secret.type == "kafka" && local.kafka_outputs_by_secret[name] != null
|
||
}
|
||
|
||
yc_sa_sources = {
|
||
for name, secret in local.secrets_map : name => try(
|
||
var.yc_service_accounts_map[try(secret.depends_on.service_account, "")],
|
||
null
|
||
)
|
||
if secret.type == "yc_sa"
|
||
}
|
||
|
||
yc_sa_key_names_by_secret = {
|
||
for name, secret in local.secrets_map : name => merge(
|
||
local.default_yc_sa_key_names,
|
||
try(secret.yc_sa_key_names, {})
|
||
)
|
||
if secret.type == "yc_sa"
|
||
}
|
||
|
||
# Явные значения секрета (adopt 1:1 / статические). Приходят прямо из
|
||
# infrastructure-secrets.yaml в поле data как map(key => base64(raw_value)).
|
||
# k8s хранит .data уже в base64, поэтому base64decode даёт исходное значение байт-в-байт.
|
||
secrets_data_override = {
|
||
for name, secret in local.secrets_map : name => {
|
||
for key, b64 in try(secret.data, {}) : key => base64decode(b64)
|
||
}
|
||
if length(try(secret.data, {})) > 0
|
||
}
|
||
|
||
secrets_data_computed = {
|
||
for name, secret in local.secrets_map : name =>
|
||
secret.type == "dockerconfigjson" ? {
|
||
".dockerconfigjson" = jsonencode({
|
||
auths = {
|
||
"${secret.registry_url}" = {
|
||
username = try(var.env_vars.DOCKER_REGISTRY_USERNAME, "")
|
||
password = try(var.env_vars.DOCKER_REGISTRY_PASSWORD, "")
|
||
auth = base64encode("${try(var.env_vars.DOCKER_REGISTRY_USERNAME, "")}:${try(var.env_vars.DOCKER_REGISTRY_PASSWORD, "")}")
|
||
}
|
||
}
|
||
})
|
||
} : secret.type == "s3" ? {
|
||
# Если указан конкретный bucket в depends_on - используем его, иначе fallback на s3_outputs
|
||
access_key = try(var.s3_buckets_map[secret.depends_on.bucket].access_key, var.s3_outputs.access_key)
|
||
secret_key = try(var.s3_buckets_map[secret.depends_on.bucket].secret_key, var.s3_outputs.secret_key)
|
||
bucket = try(var.s3_buckets_map[secret.depends_on.bucket].bucket_name, var.s3_outputs.bucket_name)
|
||
endpoint = try(var.constants.s3_endpoint, "https://storage.yandexcloud.net")
|
||
} : secret.type == "yc_sa" ? merge(
|
||
{
|
||
(local.yc_sa_key_names_by_secret[name].access_key) = try(local.yc_sa_sources[name].access_key, "")
|
||
(local.yc_sa_key_names_by_secret[name].secret_key) = try(local.yc_sa_sources[name].secret_key, "")
|
||
(local.yc_sa_key_names_by_secret[name].service_account_id) = try(local.yc_sa_sources[name].service_account_id, "")
|
||
endpoint = "https://storage.yandexcloud.net"
|
||
},
|
||
try(secret.custom_keys, {}),
|
||
{
|
||
for key, constant_name in try(secret.constant_keys, {}) : key => try(var.constants[constant_name], "")
|
||
},
|
||
{
|
||
for key, config in try(secret.random_keys, {}) : key => random_password.secrets["${name}:${key}"].result
|
||
}
|
||
) : secret.type == "database" && local.database_outputs_by_secret[name] != null ? merge(
|
||
# Базовые поля из database outputs
|
||
{
|
||
host = local.database_outputs_by_secret[name].host
|
||
port = try(var.constants.postgres_port, "6432")
|
||
database = local.database_outputs_by_secret[name].database_name
|
||
username = local.database_outputs_by_secret[name].user_name
|
||
password = local.database_outputs_by_secret[name].password
|
||
"ca.crt" = try(var.constants.postgres_ca, "")
|
||
},
|
||
# Кастомные статические поля
|
||
try(secret.custom_keys, {}),
|
||
{
|
||
for key, constant_name in try(secret.constant_keys, {}) : key => try(var.constants[constant_name], "")
|
||
},
|
||
# Рандомные поля
|
||
{
|
||
for key, config in try(secret.random_keys, {}) : key => random_password.secrets["${name}:${key}"].result
|
||
}
|
||
) : secret.type == "database_url" && local.database_outputs_by_secret[name] != null ? merge(
|
||
{
|
||
database_url = format(
|
||
"postgresql+asyncpg://%s:%s@%s:%s/%s",
|
||
local.database_outputs_by_secret[name].user_name,
|
||
local.database_outputs_by_secret[name].password,
|
||
local.database_outputs_by_secret[name].host,
|
||
try(var.constants.postgres_port, "6432"),
|
||
local.database_outputs_by_secret[name].database_name
|
||
)
|
||
},
|
||
try(secret.custom_keys, {}),
|
||
{
|
||
for key, constant_name in try(secret.constant_keys, {}) : key => try(var.constants[constant_name], "")
|
||
},
|
||
{
|
||
for key, config in try(secret.random_keys, {}) : key => random_password.secrets["${name}:${key}"].result
|
||
}
|
||
) : secret.type == "valkey" && local.valkey_outputs_by_secret[name] != null ? merge(
|
||
{
|
||
cert = try(var.constants.valkey_ca, try(var.constants.postgres_ca, ""))
|
||
host = local.valkey_outputs_by_secret[name].host
|
||
login = local.valkey_outputs_by_secret[name].user_name
|
||
password = local.valkey_outputs_by_secret[name].password
|
||
port = tostring(try(local.valkey_outputs_by_secret[name].port, try(var.constants.valkey_port, "6380")))
|
||
url = format("%s:%s", local.valkey_outputs_by_secret[name].host, tostring(try(local.valkey_outputs_by_secret[name].port, try(var.constants.valkey_port, "6380"))))
|
||
},
|
||
try(secret.custom_keys, {}),
|
||
{
|
||
for key, constant_name in try(secret.constant_keys, {}) : key => try(var.constants[constant_name], "")
|
||
},
|
||
{
|
||
for key, config in try(secret.random_keys, {}) : key => random_password.secrets["${name}:${key}"].result
|
||
}
|
||
) : secret.type == "rabbitmq" && local.rabbitmq_outputs_by_secret[name] != null ? merge(
|
||
local.rabbitmq_credentials_by_secret[name],
|
||
try(secret.custom_keys, {}),
|
||
{
|
||
for key, constant_name in try(secret.constant_keys, {}) : key => try(var.constants[constant_name], "")
|
||
},
|
||
{
|
||
for key, config in try(secret.random_keys, {}) : key => random_password.secrets["${name}:${key}"].result
|
||
}
|
||
) : secret.type == "kafka" && local.kafka_outputs_by_secret[name] != null ? merge(
|
||
local.kafka_credentials_by_secret[name],
|
||
try(secret.custom_keys, {}),
|
||
{
|
||
for key, constant_name in try(secret.constant_keys, {}) : key => try(var.constants[constant_name], "")
|
||
},
|
||
{
|
||
for key, config in try(secret.random_keys, {}) : key => random_password.secrets["${name}:${key}"].result
|
||
}
|
||
) : merge(
|
||
try(secret.custom_keys, {}),
|
||
{
|
||
for key, constant_name in try(secret.constant_keys, {}) : key => try(var.constants[constant_name], "")
|
||
},
|
||
{
|
||
for key, config in try(secret.random_keys, {}) : key => random_password.secrets["${name}:${key}"].result
|
||
}
|
||
)
|
||
}
|
||
|
||
# Если для секрета заданы явные значения (data) - используем их 1:1,
|
||
# иначе собираем data из outputs/custom/constant/random как обычно.
|
||
secrets_data = {
|
||
for name, secret in local.secrets_map : name => (
|
||
contains(keys(local.secrets_data_override), name)
|
||
? local.secrets_data_override[name]
|
||
: local.secrets_data_computed[name]
|
||
)
|
||
}
|
||
|
||
secrets_with_data = {
|
||
for name, secret in local.secrets_map : name => {
|
||
name = secret.name
|
||
namespace = secret.namespace
|
||
type = secret.type
|
||
k8s_type = try(local.k8s_secret_type_map[secret.type], "Opaque")
|
||
labels = try(secret.labels, {})
|
||
annotations = try(secret.annotations, {})
|
||
ignore_changes = try(secret.ignore_changes, false)
|
||
data = try(local.secrets_data[name], {})
|
||
}
|
||
}
|
||
|
||
secrets_with_ignore = {
|
||
for name, secret in local.secrets_with_data : name => secret
|
||
if secret.ignore_changes
|
||
}
|
||
secrets_without_ignore = {
|
||
for name, secret in local.secrets_with_data : name => secret
|
||
if !secret.ignore_changes
|
||
}
|
||
}
|
||
|
||
resource "random_password" "secrets" {
|
||
for_each = local.random_keys_flat
|
||
|
||
length = each.value.length
|
||
special = each.value.special
|
||
upper = true
|
||
lower = true
|
||
numeric = true
|
||
|
||
lifecycle {
|
||
ignore_changes = all
|
||
}
|
||
}
|
||
|
||
resource "kubernetes_secret" "with_ignore" {
|
||
for_each = local.secrets_with_ignore
|
||
|
||
metadata {
|
||
name = each.value.name
|
||
namespace = each.value.namespace
|
||
labels = try(each.value.labels, {})
|
||
annotations = try(each.value.annotations, {})
|
||
}
|
||
|
||
type = each.value.k8s_type
|
||
|
||
data = each.value.data
|
||
|
||
lifecycle {
|
||
# Игнорируем data, type и metadata чтобы не было phantom updates
|
||
ignore_changes = [data, type, metadata, wait_for_service_account_token]
|
||
}
|
||
|
||
depends_on = [random_password.secrets]
|
||
}
|
||
|
||
resource "kubernetes_secret" "without_ignore" {
|
||
for_each = local.secrets_without_ignore
|
||
|
||
metadata {
|
||
name = each.value.name
|
||
namespace = each.value.namespace
|
||
labels = try(each.value.labels, {})
|
||
annotations = try(each.value.annotations, {})
|
||
}
|
||
|
||
type = each.value.k8s_type
|
||
|
||
data = each.value.data
|
||
|
||
lifecycle {
|
||
# type и metadata игнорируем чтобы не было phantom updates
|
||
ignore_changes = [type, metadata, wait_for_service_account_token]
|
||
}
|
||
|
||
depends_on = [random_password.secrets]
|
||
}
|