Pular para o conteúdo principal

O output de um módulo

Por que o output de um módulo é um objeto aninhado e não uma lista de valores soltos, e até onde o aninhamento vai.

Um módulo publica o que criou por meio de output, e a forma desse output é a decisão mais duradoura do módulo inteiro: ela é o contrato com toda composição que o usa, e mudá-la depois custa um apply em cada consumidor. A escolha entre publicar valores soltos e publicar um objeto parece estética na primeira semana e deixa de ser na primeira mudança.

Por que objeto e não valores soltos

Um módulo que publica bucket_nome, bucket_arn, bucket_regiao e bucket_kms_arn obriga cada consumidor a saber os quatro nomes. Acrescentar um quinto é aditivo, mas renomear qualquer um é quebra, e a chance de renomear cresce com o número de nomes no escopo raiz.

Um objeto único move o vocabulário para dentro de uma chave, e o consumidor passa a depender de um nome só.

FormaNomes no escopo raizAcrescentar campoRenomear campo
valores soltosum por campoaditivoquebra
objeto raso1aditivoquebra
objeto aninhado1aditivoquebra, e localizada

A anatomia, quatro níveis

Este é o output do módulo de bucket, e ele é o aninhamento mais profundo que a casa usa. Quatro níveis é o teto: o quinto não apareceu em nenhum módulo, e um teto declarado é o que impede o output de virar um mapa do provedor inteiro.

#bucketobject

Tudo o que o módulo criou, sob uma chave só.

campos

#nomestring

O nome final, já com o sufixo de ambiente aplicado.

#arnstring

O identificador global, para uso em política.

#criptografiaobject

A chave e o modo. Sempre presente: o módulo não cria bucket sem criptografia.

campos

#modostringpadrão kms

kms ou sse-s3. O módulo recusa nenhuma.

#chaveobject

A chave usada, e de onde ela veio.

campos

#arnstring

O identificador da chave.

#gerenciada_porstring

modulo quando o módulo a criou, equipe quando ela foi passada por variável. É este campo que diz quem apaga a chave no dia em que o bucket for destruído.

Como ele é declarado

output "bucket" {
description = "O bucket criado e as decisões aplicadas a ele."
value = {
nome = aws_s3_bucket.este.bucket
arn = aws_s3_bucket.este.arn
criptografia = {
modo = var.modo_de_criptografia
chave = {
arn = local.chave_arn
gerenciada_por = var.chave_arn == null ? "modulo" : "equipe"
}
}
}
}

Como ele é consumido

module "relatorios" {
source = "panlabs/bucket/aws"
version = "3.1.0"
nome = "relatorios"
}

resource "aws_iam_role_policy" "leitura" {
role = aws_iam_role.servico.id
policy = data.aws_iam_policy_document.leitura.json
}

data "aws_iam_policy_document" "leitura" {
statement {
actions = ["s3:GetObject"]
resources = ["${module.relatorios.bucket.arn}/*"]
}
statement {
actions = ["kms:Decrypt"]
resources = [module.relatorios.bucket.criptografia.chave.arn]
}
}

module.relatorios.bucket.criptografia.chave.arn é o caminho mais longo que existe na casa, e ele é o teto por decisão, não por acaso. Um quinto nível significaria que o módulo está publicando estrutura do provedor em vez de publicar as decisões dele.