mirror of
https://gitlab.sarex.io/infra/terraform-contour-mirror.git
synced 2026-08-05 18:31:00 +03:00
add SA creation logic
This commit is contained in:
parent
31c3bf338a
commit
3286b26777
@ -59,6 +59,19 @@ environments:
|
||||
# lifecycle:
|
||||
# ignore_changes: false
|
||||
|
||||
# # Пример секрета из SA ключей
|
||||
# - name: dwg-sa-secret
|
||||
# namespace: pulse
|
||||
# type: yc_sa
|
||||
# dependencies:
|
||||
# service_account: dwg-sa
|
||||
# yc_sa_key_names: # как назвать ключи в секрете
|
||||
# access_key: access_key
|
||||
# secret_key: secret_key
|
||||
# service_account_id: sa_id
|
||||
# lifecycle:
|
||||
# ignore_changes: false
|
||||
|
||||
buckets:
|
||||
- name: pulse-prod
|
||||
acl: private
|
||||
@ -66,8 +79,14 @@ environments:
|
||||
enabled: false
|
||||
cors:
|
||||
enabled: false
|
||||
|
||||
|
||||
|
||||
# yc_service_accounts:
|
||||
# - name: dwg-sa
|
||||
# description: "DWG SA Uploader"
|
||||
# folder_roles:
|
||||
# - storage.uploader
|
||||
# create_static_access_key: true
|
||||
|
||||
|
||||
databases:
|
||||
- cluster_id: "c9quu72dj2ibu8dk54q5"
|
||||
@ -81,4 +100,3 @@ environments:
|
||||
password_special: false
|
||||
conn_limit: 10
|
||||
|
||||
|
||||
|
||||
@ -20,8 +20,9 @@ terraform {
|
||||
}
|
||||
|
||||
inputs = {
|
||||
buckets = local.env_config.buckets
|
||||
folder_id = get_env("YC_PROD_FOLDER_ID", get_env("YC_FOLDER_ID", ""))
|
||||
buckets = local.env_config.buckets
|
||||
yc_service_accounts = try(local.env_config.yc_service_accounts, [])
|
||||
folder_id = get_env("YC_PROD_FOLDER_ID", get_env("YC_FOLDER_ID", ""))
|
||||
|
||||
yc_token = get_env("YC_TOKEN", "")
|
||||
yc_service_account_key_file = get_env("YC_SERVICE_ACCOUNT_KEY_FILE", "")
|
||||
|
||||
@ -21,10 +21,11 @@ dependency "namespace" {
|
||||
dependency "s3" {
|
||||
config_path = "../s3"
|
||||
mock_outputs = {
|
||||
bucket_name = "mock-bucket"
|
||||
access_key = "mock-access-key"
|
||||
secret_key = "mock-secret-key"
|
||||
buckets = {}
|
||||
bucket_name = "mock-bucket"
|
||||
access_key = "mock-access-key"
|
||||
secret_key = "mock-secret-key"
|
||||
buckets = {}
|
||||
service_accounts = {}
|
||||
}
|
||||
mock_outputs_allowed_terraform_commands = ["init", "validate", "plan"]
|
||||
skip_outputs = get_env("TG_SKIP_DEPENDENCY_OUTPUTS", "false") == "true"
|
||||
@ -115,16 +116,17 @@ terraform {
|
||||
inputs = {
|
||||
secrets = [
|
||||
for secret in local.env_config.secrets : {
|
||||
name = secret.name
|
||||
namespace = secret.namespace
|
||||
secret_type = secret.type
|
||||
registry_url = try(secret.registry_url, "")
|
||||
dependencies = try(secret.dependencies, {})
|
||||
custom_keys = try(secret.custom_keys, {})
|
||||
random_keys = try(secret.random_keys, {})
|
||||
labels = try(secret.labels, {})
|
||||
annotations = try(secret.annotations, {})
|
||||
ignore_changes = try(secret.lifecycle.ignore_changes, false)
|
||||
name = secret.name
|
||||
namespace = secret.namespace
|
||||
secret_type = secret.type
|
||||
registry_url = try(secret.registry_url, "")
|
||||
dependencies = try(secret.dependencies, {})
|
||||
yc_sa_key_names = try(secret.yc_sa_key_names, {})
|
||||
custom_keys = try(secret.custom_keys, {})
|
||||
random_keys = try(secret.random_keys, {})
|
||||
labels = try(secret.labels, {})
|
||||
annotations = try(secret.annotations, {})
|
||||
ignore_changes = try(secret.lifecycle.ignore_changes, false)
|
||||
}
|
||||
]
|
||||
|
||||
@ -134,7 +136,8 @@ inputs = {
|
||||
secret_key = dependency.s3.outputs.secret_key
|
||||
}
|
||||
|
||||
s3_buckets_map = dependency.s3.outputs.buckets
|
||||
s3_buckets_map = dependency.s3.outputs.buckets
|
||||
yc_service_accounts_map = try(dependency.s3.outputs.service_accounts, {})
|
||||
|
||||
database_outputs_map = dependency.database.outputs.database_outputs_map
|
||||
|
||||
|
||||
@ -6,13 +6,20 @@ locals {
|
||||
"dockerconfigjson" = "kubernetes.io/dockerconfigjson"
|
||||
"database" = "Opaque"
|
||||
"s3" = "Opaque"
|
||||
"yc_sa" = "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 idx, secret in var.secrets : 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}" => {
|
||||
@ -23,56 +30,82 @@ locals {
|
||||
}
|
||||
}
|
||||
]...)
|
||||
|
||||
|
||||
database_outputs_by_secret = {
|
||||
for name, secret in local.secrets_map : name => try(
|
||||
var.database_outputs_map["${try(secret.dependencies.cluster, "")}:${try(secret.dependencies.db, "")}:${try(secret.dependencies.user, "")}"],
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
secrets_data = {
|
||||
for name, secret in local.secrets_map : name =>
|
||||
secret.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.secret_type == "s3" ? {
|
||||
# Если указан конкретный bucket в dependencies - используем его, иначе fallback на s3_outputs
|
||||
access_key = try(var.s3_buckets_map[secret.dependencies.bucket].access_key, var.s3_outputs.access_key)
|
||||
secret_key = try(var.s3_buckets_map[secret.dependencies.bucket].secret_key, var.s3_outputs.secret_key)
|
||||
bucket = try(var.s3_buckets_map[secret.dependencies.bucket].bucket_name, var.s3_outputs.bucket_name)
|
||||
endpoint = try(var.constants.s3_endpoint, "https://storage.yandexcloud.net")
|
||||
} : secret.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, config in try(secret.random_keys, {}) : key => random_password.secrets["${name}:${key}"].result
|
||||
}
|
||||
) : merge(
|
||||
try(secret.custom_keys, {}),
|
||||
{
|
||||
for key, config in try(secret.random_keys, {}) : key => random_password.secrets["${name}:${key}"].result
|
||||
}
|
||||
)
|
||||
|
||||
yc_sa_sources = {
|
||||
for name, secret in local.secrets_map : name => try(
|
||||
var.yc_service_accounts_map[try(secret.dependencies.service_account, "")],
|
||||
null
|
||||
)
|
||||
if secret.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.secret_type == "yc_sa"
|
||||
}
|
||||
|
||||
secrets_data = {
|
||||
for name, secret in local.secrets_map : name =>
|
||||
secret.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.secret_type == "s3" ? {
|
||||
# Если указан конкретный bucket в dependencies - используем его, иначе fallback на s3_outputs
|
||||
access_key = try(var.s3_buckets_map[secret.dependencies.bucket].access_key, var.s3_outputs.access_key)
|
||||
secret_key = try(var.s3_buckets_map[secret.dependencies.bucket].secret_key, var.s3_outputs.secret_key)
|
||||
bucket = try(var.s3_buckets_map[secret.dependencies.bucket].bucket_name, var.s3_outputs.bucket_name)
|
||||
endpoint = try(var.constants.s3_endpoint, "https://storage.yandexcloud.net")
|
||||
} : secret.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, "")
|
||||
},
|
||||
try(secret.custom_keys, {}),
|
||||
{
|
||||
for key, config in try(secret.random_keys, {}) : key => random_password.secrets["${name}:${key}"].result
|
||||
}
|
||||
) : secret.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, config in try(secret.random_keys, {}) : key => random_password.secrets["${name}:${key}"].result
|
||||
}
|
||||
) : merge(
|
||||
try(secret.custom_keys, {}),
|
||||
{
|
||||
for key, config in try(secret.random_keys, {}) : key => random_password.secrets["${name}:${key}"].result
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
secrets_with_data = {
|
||||
for name, secret in local.secrets_map : name => {
|
||||
name = secret.name
|
||||
@ -85,7 +118,7 @@ locals {
|
||||
data = try(local.secrets_data[name], {})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
secrets_with_ignore = {
|
||||
for name, secret in local.secrets_with_data : name => secret
|
||||
if secret.ignore_changes
|
||||
@ -98,7 +131,7 @@ locals {
|
||||
|
||||
resource "random_password" "secrets" {
|
||||
for_each = local.random_keys_flat
|
||||
|
||||
|
||||
length = each.value.length
|
||||
special = each.value.special
|
||||
upper = true
|
||||
|
||||
@ -1,23 +1,29 @@
|
||||
variable "secrets" {
|
||||
description = "Список секретов для создания"
|
||||
type = list(object({
|
||||
name = string
|
||||
namespace = string
|
||||
secret_type = string
|
||||
registry_url = optional(string, "")
|
||||
dependencies = optional(object({
|
||||
cluster = optional(string, "")
|
||||
db = optional(string, "")
|
||||
user = optional(string, "")
|
||||
bucket = optional(string, "") # Имя бакета для s3 секретов
|
||||
}), {})
|
||||
custom_keys = optional(map(string), {})
|
||||
random_keys = optional(map(object({
|
||||
name = string
|
||||
namespace = string
|
||||
secret_type = string
|
||||
registry_url = optional(string, "")
|
||||
dependencies = optional(object({
|
||||
cluster = optional(string, "")
|
||||
db = optional(string, "")
|
||||
user = optional(string, "")
|
||||
bucket = optional(string, "") # Имя бакета для s3 секретов
|
||||
service_account = optional(string, "") # Имя YC Service Account для yc_sa секретов
|
||||
}), {})
|
||||
yc_sa_key_names = optional(object({
|
||||
access_key = optional(string, "access_key")
|
||||
secret_key = optional(string, "secret_key")
|
||||
service_account_id = optional(string, "service_account_id")
|
||||
}), {})
|
||||
custom_keys = optional(map(string), {})
|
||||
random_keys = optional(map(object({
|
||||
length = optional(number, 32)
|
||||
special = optional(bool, false)
|
||||
})), {}) # Случайные ключи
|
||||
labels = optional(map(string), {})
|
||||
annotations = optional(map(string), {})
|
||||
labels = optional(map(string), {})
|
||||
annotations = optional(map(string), {})
|
||||
ignore_changes = optional(bool, false)
|
||||
}))
|
||||
}
|
||||
@ -47,25 +53,36 @@ variable "s3_buckets_map" {
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "yc_service_accounts_map" {
|
||||
description = "Map YC service accounts (name => data)"
|
||||
type = map(object({
|
||||
service_account_id = string
|
||||
access_key = optional(string, "")
|
||||
secret_key = optional(string, "")
|
||||
folder_roles = optional(list(string), [])
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "database_outputs_map" {
|
||||
description = "Outputs от модулей Database, ключ = cluster_id:database_name:user_name"
|
||||
type = map(object({
|
||||
host = string
|
||||
host = string
|
||||
database_name = string
|
||||
user_name = string
|
||||
password = string
|
||||
user_name = string
|
||||
password = string
|
||||
}))
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "constants" {
|
||||
description = "Константные значения (CA сертификаты, endpoints и т.д.)"
|
||||
type = map(string)
|
||||
default = {}
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "env_vars" {
|
||||
description = "Environment variables"
|
||||
type = map(string)
|
||||
default = {}
|
||||
type = map(string)
|
||||
default = {}
|
||||
}
|
||||
|
||||
@ -1,5 +1,20 @@
|
||||
locals {
|
||||
buckets_map = { for bucket in var.buckets : bucket.name => bucket }
|
||||
buckets_map = { for bucket in var.buckets : bucket.name => bucket }
|
||||
yc_service_accounts_map = { for sa in var.yc_service_accounts : sa.name => sa }
|
||||
|
||||
yc_service_account_folder_roles = length(local.yc_service_accounts_map) > 0 ? merge([
|
||||
for sa_name, sa in local.yc_service_accounts_map : {
|
||||
for role in try(sa.folder_roles, []) : "${sa_name}:${role}" => {
|
||||
sa_name = sa_name
|
||||
role = role
|
||||
}
|
||||
}
|
||||
]...) : {}
|
||||
|
||||
yc_service_accounts_with_static_key = {
|
||||
for sa_name, sa in local.yc_service_accounts_map : sa_name => sa
|
||||
if try(sa.create_static_access_key, true)
|
||||
}
|
||||
}
|
||||
|
||||
resource "yandex_iam_service_account" "sa" {
|
||||
@ -54,3 +69,25 @@ resource "yandex_storage_bucket_iam_binding" "uploader" {
|
||||
|
||||
depends_on = [yandex_storage_bucket.this]
|
||||
}
|
||||
|
||||
resource "yandex_iam_service_account" "custom_sa" {
|
||||
for_each = local.yc_service_accounts_map
|
||||
|
||||
name = each.value.name
|
||||
description = try(each.value.description, "")
|
||||
}
|
||||
|
||||
resource "yandex_resourcemanager_folder_iam_member" "custom_sa_role" {
|
||||
for_each = local.yc_service_account_folder_roles
|
||||
|
||||
folder_id = var.folder_id
|
||||
role = each.value.role
|
||||
member = "serviceAccount:${yandex_iam_service_account.custom_sa[each.value.sa_name].id}"
|
||||
}
|
||||
|
||||
resource "yandex_iam_service_account_static_access_key" "custom_sa_key" {
|
||||
for_each = local.yc_service_accounts_with_static_key
|
||||
|
||||
service_account_id = yandex_iam_service_account.custom_sa[each.key].id
|
||||
description = "Static access key for ${each.key}"
|
||||
}
|
||||
|
||||
@ -27,3 +27,16 @@ output "buckets" {
|
||||
}
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
output "service_accounts" {
|
||||
description = "Map of additional YC service accounts (name => data)"
|
||||
value = {
|
||||
for name, sa in yandex_iam_service_account.custom_sa : name => {
|
||||
service_account_id = sa.id
|
||||
access_key = try(yandex_iam_service_account_static_access_key.custom_sa_key[name].access_key, "")
|
||||
secret_key = try(yandex_iam_service_account_static_access_key.custom_sa_key[name].secret_key, "")
|
||||
folder_roles = try(local.yc_service_accounts_map[name].folder_roles, [])
|
||||
}
|
||||
}
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
@ -18,6 +18,17 @@ variable "buckets" {
|
||||
}))
|
||||
}
|
||||
|
||||
variable "yc_service_accounts" {
|
||||
description = "Additional Yandex Cloud service accounts with optional folder roles and static keys"
|
||||
type = list(object({
|
||||
name = string
|
||||
description = optional(string, "")
|
||||
folder_roles = optional(list(string), [])
|
||||
create_static_access_key = optional(bool, true)
|
||||
}))
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "folder_id" {
|
||||
description = "Yandex Cloud folder ID"
|
||||
type = string
|
||||
|
||||
Loading…
Reference in New Issue
Block a user