Blog Sobre
↼ Voltar para a lista

Dica TF: Você pode usar JSON para declarar objetos no Terraform

Feb 10, 2025 - 2 min read

Não é segredo que o terraform é compatível com o JSON. Ou ainda melhor, que o HCL é compatível com o JSON, possuindo a sua própria sintaxe JSON. Essas documentações são principalmente focadas, como seus nomes sugerem, na sintaxe HCL e em como se pode declarar nela recursos, variáveis, etc.

Isso traz uma consequência interessante, no entanto. Você pode usar JSON para declarar objetos no Terraform.

O exemplo abaixo foi retirado da documentação do resource aws_iam_role e atualizado para usar a sintaxe JSON. É um código Terraform perfeitamente válido.

resource "aws_iam_role" "test_role" {
  name = "test_role"

  # A função "jsonencode" converte
  # o resultado da expressão Terraform para uma string JSON válida.
  assume_role_policy = jsonencode({
    "Version": "2012-10-17",
    "Statement": [
      {
        "Action": "sts:AssumeRole",
        "Effect": "Allow",
        "Sid": "",
        "Principal": {
          "Service": "ec2.amazonaws.com"
        }
      },
    ]
  })

  tags = {
    tag-key = "tag-value"
  }
}

É um truque particularmente útil quando você está integrando a configuração de resources que aceitam JSON como entrada, como o atributo assume_role_policy do resource aws_iam_role, e evita a necessidade de converter a sintaxe JSON para HCL, declarar o objeto JSON em um arquivo separado ou usar recursos alternativos, como o data source aws_iam_role_policy_document. Também é mais fácil de ler do que usar strings Heredoc ou uma string JSON inline (onde você precisaria escapar as aspas).

Como bônus, você pode misturar a sintaxe JSON com expressões Terraform - HCL e JSON são intercambiáveis nesse caso. Por exemplo, poderíamos usar o abaixo para declarar a política de um determinado repositório ECR, permitindo a extração de imagens de uma lista de contas. Isso está mais próximo dos exemplos de políticas IAM que você pode encontrar na documentação da AWS.

resource "aws_ecr_repository" "test_repo" {
  name = "test_repo"

  repository_policy_text = jsonencode({
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "AllowPull",
        "Effect": "Allow",
        "Principal": {
            "AWS": [
                for account_id in var.account_ids :
                "arn:aws:iam::${account_id}:root"
            ]
        },
        "Action": [
            "ecr:BatchGetImage",
            "ecr:GetDownloadUrlForLayer"
        ]
      }
    ]
  })
}

Isso é tudo, e é algo que venho usando há bastante tempo e que não encontrei muitas discussões sobre. Espero que você ache essa dica útil e que ela possa te economizar algum tempo. Boa codificação!