linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
Intro
Lessons
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Уроки
  • How it works
  • База знаний
  • Шпаргалка
  • Capstone
  • Собеседование
home/terraform/lessons/tf-intermediate-05-templatefile

lesson ── terraform-intermediate ── ~14 мин ── 5 шагов

templatefile: рендерим конфиги из HCL

Часто Terraform надо отдать «текстовый файл с подстановками», bash-скрипт в user_data EC2, JSON-policy для IAM, YAML для cloud-init. Inline в HCL тяжело читать. Зашить в .tf готовый текст, нельзя, нужны подстановки.

templatefile() решает: читает файл шаблона, подставляет переменные, возвращает строку. В этом уроке отрендеришь IAM-policy из шаблона.

▶ интерактивный sandbox

Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.

запустить sandbox →

stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя

Шаги

  1. 01

    Напиши шаблон IAM-policy

    Создай файл templates/bucket-rw-policy.json.tpl:

    bash
    cd /home/student/tf-template
    cat > templates/bucket-rw-policy.json.tpl <<'EOF'
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "ReadBucket",
          "Effect": "Allow",
          "Action": [
            "s3:GetObject",
            "s3:ListBucket"
          ],
          "Resource": [
            "${bucket_arn}",
            "${bucket_arn}/*"
          ]
        }%{ if write_enabled },
        {
          "Sid": "WriteBucket",
          "Effect": "Allow",
          "Action": [
            "s3:PutObject",
            "s3:DeleteObject"
          ],
          "Resource": "${bucket_arn}/*"
        }%{ endif }
      ]
    }
    EOF

    Синтаксис:

    • ${var}, простая подстановка.
    • %{ if cond }...%{ endif }, условный блок. Тут добавляется второй Statement только если write_enabled = true.
    • %{ for x in list }...%{ endfor }, цикл (тут не используем, но бывает).

    Файл .tpl, просто условие. Можно .tftpl или без расширения. Расширение .tpl или .tftpl, чтобы IDE/git-tools знали что это шаблон, не финальный JSON.

    ✓ Шаблон записан. Теперь: рендер в HCL.

  2. 02

    Подключи templatefile в HCL

    В /home/student/tf-template/main.tf:

    hcl
    resource "random_id" "suffix" {
      byte_length = 4
    }
    resource "aws_s3_bucket" "demo" {
      bucket = "linuxlab-template-${random_id.suffix.hex}"
    }
    locals {
      bucket_policy_json = templatefile(
        "${path.module}/templates/bucket-rw-policy.json.tpl",
        {
          bucket_arn    = aws_s3_bucket.demo.arn
          write_enabled = true
        },
      )
    }
    resource "aws_iam_policy" "bucket_rw" {
      name   = "linuxlab-template-rw-${random_id.suffix.hex}"
      policy = local.bucket_policy_json
    }
    output "policy_json" {
      value = local.bucket_policy_json
    }

    Что важно:

    • path.module, абсолютный путь к директории текущего модуля (тут root). Не пиши абсолютный путь руками, используй path.module.
    • Передаём bucket_arn из ресурса, который ещё не создан. Terraform автоматически выстроит зависимость: policy создастся после бакета. См. tf-depends-on.
    • Результат шаблонизации, обычная строка. Кладём в aws_iam_policy.policy.

    ✓ HCL готов. Теперь рендер можно увидеть через console.

  3. 03

    Проверь рендер через console (до apply)

    Можно посмотреть результат рендера не делая apply:

    bash
    cd /home/student/tf-template
    terraform init
    echo 'templatefile("${path.module}/templates/bucket-rw-policy.json.tpl", { bucket_arn = "arn:aws:s3:::test-bucket", write_enabled = true })' | terraform console -no-color

    Console выведет JSON с подставленным ARN. Можешь проиграть с write_enabled = false, увидишь, что второй Statement исчезает.

    Это главный способ дебага шаблонов. Не запускай apply чтобы понять, правильно ли отрендерилось, спроси console.

    См. tf-console.

    ✓ Рендер виден до apply. Это сэкономит часы дебага.

  4. 04

    Apply: policy создаётся с правильным ARN

    bash
    terraform apply -auto-approve

    Должны создаться: бакет, IAM policy, random_id.

    Проверь policy через AWS CLI (LocalStack):

    bash
    aws --endpoint-url=http://localstack:4566 iam list-policies | jq '.Policies[] | select(.PolicyName | startswith("linuxlab-template"))'

    И через terraform output:

    bash
    terraform output -raw policy_json | jq .

    Видишь итоговый JSON со всеми подстановками.

    ✓ IAM-policy создана из шаблона. templatefile в боевых условиях.

    То же самое на OpenTofu

    OpenTofu держит CLI и state совместимыми с Terraform по командам этого шага: миграция обычно проходит через mv .terraform .terraform.bak; tofu init -upgrade. Но при первом переходе сделай backup state и прогон на feature-branch - расхождения концентрируются в новых фичах (variables в backend, state-encryption, OCI registry-backed модули). См. tf-opentofu-parity для полной матрицы.

    • → OpenTofu parity
  5. 05

    Попробуй without-write вариант

    Поменяй в HCL:

    hcl
    locals {
      bucket_policy_json = templatefile(
        "${path.module}/templates/bucket-rw-policy.json.tpl",
        {
          bucket_arn    = aws_s3_bucket.demo.arn
          write_enabled = false   # ← было true
        },
      )
    }
    bash
    terraform plan

    Plan покажет diff: вторая Statement-секция (WriteBucket) исчезает из policy JSON. Terraform увидит это как изменение атрибута policy у aws_iam_policy.bucket_rw.

    bash
    terraform apply -auto-approve

    Это главное преимущество templatefile: одно изменение HCL → детерминированный re-render → понятный diff в plan'е.

    ✓ Conditional блок отработал. Policy перевыпустилась без write-разрешений.

    templatefile vs file vs inline

    Три способа собрать строку в HCL:

    hcl
    # 1) inline в HCL, heredoc
    policy = <<-EOT
      { "Version": "2012-10-17", ... }
    EOT

    Хорошо для маленьких и без переменных. Плохо для больших. IDE не умеет в подсветку JSON внутри heredoc.

    hcl
    # 2) file(): внешний файл, без подстановок
    policy = file("${path.module}/policy.json")

    IDE подсвечивает .json. Но это статика, если нужны подстановки (ARN бакета, имя env), не сработает.

    hcl
    # 3) templatefile(): внешний файл с подстановками
    policy = templatefile("${path.module}/policy.json.tpl", { ... })

    Лучшее из обоих миров. IDE подсвечивает (если расширение .tpl/.tftpl зарегистрировано как JSON-с-шаблоном). Подстановки работают.

    Правило: templatefile для всего что больше 5-7 строк или содержит подстановки. heredoc/file, для тривиальных случаев.

    • → Строковые функции
    • → templatefile + user_data

Что ты узнал

templatefile(path, vars) читает файл с ${var} и %{ for } синтаксисом, возвращает строку. Удобно для крупных текстовых артефактов с подстановками. Не путать с template_file data source, он устаревший с TF 0.12.

команды

  • terraform consoleпроверить рендер шаблона до plan
  • terraform planвидишь итоговое значение в plan'е (если не sensitive)

концепции

  • · templatefile: функция, не data source; читается на этапе plan
  • · Внутри шаблона нет доступа к variables: только к переданным vars
  • · Для большой полезной нагрузки + base64 удобно: filebase64() / base64encode(templatefile(...))

← предыдущий

Troubleshooting Garden: модуль протух, провайдер обновился

следующий →

Checkov, security-сканер HCL

Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки