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-11-utility-providers

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

Утилитарные провайдеры: random, time, archive, external

Четыре утилитарных провайдера, без которых не обходится практический HCL: random (уникальные имена и пароли), time (метки и задержки), archive (упаковка lambda-кода), external (вызов любого скрипта). В этом уроке используешь все четыре в одном проекте. Это типичный «зоопарк» reusable-блоков.

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

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

запустить sandbox →

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

Шаги

  1. 01

    Положи минимальную Lambda и упакуй её

    bash
    cd /home/student/tf-utility
    cat > lambda-src/handler.py <<'EOF'
    def main(event, context):
        return {"statusCode": 200, "body": "hello from terraformlab"}
    EOF
    ls lambda-src/

    Дальше. Terraform-часть. В main.tf:

    hcl
    terraform {
      required_providers {
        archive = {
          source  = "hashicorp/archive"
          version = "~> 2.6"
        }
        random = {
          source  = "hashicorp/random"
          version = "~> 3.6"
        }
        time = {
          source  = "hashicorp/time"
          version = "~> 0.12"
        }
      }
    }
    data "archive_file" "lambda" {
      type        = "zip"
      source_file = "${path.module}/lambda-src/handler.py"
      output_path = "${path.module}/lambda.zip"
    }

    Запусти init + плана:

    bash
    terraform init
    terraform plan

    Plan покажет что data.archive_file будет прочитан. Файл lambda.zip создаст сам провайдер на этапе apply.

    ✓ archive_file прописан. Теперь добавим остальные провайдеры.

  2. 02

    random для уникального имени, time для timestamp

    Добавь в main.tf:

    hcl
    resource "random_id" "fn_suffix" {
      byte_length = 4
    }
    resource "random_password" "api_key" {
      length  = 24
      special = false
    }
    resource "time_static" "created_at" {}
    locals {
      function_name = "linuxlab-utility-${random_id.fn_suffix.hex}"
      created_date  = formatdate("YYYY-MM-DD", time_static.created_at.rfc3339)
    }

    Что происходит:

    • random_id.fn_suffix.hex, 8 hex-символов, уникальные при создании, стабильные между apply (записаны в state).
    • random_password.api_key.result, пароль длиной 24, без спецсимволов. Помечен sensitive автоматически.
    • time_static.created_at, фиксирует timestamp при первом apply. Дальше не меняется.

    См. tf-utility-providers.

    ✓ Random + time прописаны. Теперь создадим Lambda и положим её на S3.

  3. 03

    Создай Lambda с упакованным кодом

    Добавь в main.tf:

    hcl
    resource "aws_iam_role" "lambda" {
      name = "${local.function_name}-role"
      assume_role_policy = jsonencode({
        Version = "2012-10-17"
        Statement = [{
          Action = "sts:AssumeRole"
          Effect = "Allow"
          Principal = { Service = "lambda.amazonaws.com" }
        }]
      })
    }
    resource "aws_lambda_function" "demo" {
      function_name    = local.function_name
      filename         = data.archive_file.lambda.output_path
      source_code_hash = data.archive_file.lambda.output_base64sha256
      handler          = "handler.main"
      runtime          = "python3.12"
      role             = aws_iam_role.lambda.arn
      environment {
        variables = {
          API_KEY      = random_password.api_key.result
          CREATED_DATE = local.created_date
        }
      }
      tags = {
        CreatedAt = local.created_date
      }
    }
    output "function_name" {
      value = aws_lambda_function.demo.function_name
    }

    Главное:

    • source_code_hash = data.archive_file.lambda.output_base64sha256, triggerит апдейт Lambda при изменении кода. Без него Terraform не заметит правки в handler.py.
    • random_password.api_key.result идёт в env Lambda. В state он в открытом виде.
    • local.created_date, рассчитанная локаль из time_static.
    bash
    terraform apply -auto-approve

    ✓ Lambda создана с уникальным именем и timestamp.

  4. 04

    Поменяй код Lambda: autoupdate

    Покажем, что source_code_hash работает: поменяем код handler'а.

    bash
    cat > lambda-src/handler.py <<'EOF'
    def main(event, context):
        return {"statusCode": 200, "body": "hello v2"}
    EOF
    terraform plan

    Plan покажет:

    # aws_lambda_function.demo will be updated in-place
      ~ source_code_hash = "..." -> "..."

    Terraform увидел что hash изменился (потому что код изменился) и хочет обновить Lambda. Без source_code_hash он бы не заметил, filename тот же.

    bash
    terraform apply -auto-approve

    Lambda перевыкатилась с новым кодом.

    ✓ Lambda обновилась. archive_file + source_code_hash работает.

    То же самое на 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

    Принудительная регенерация random_id

    Иногда нужно «новый suffix, новый бакет, всё свежее». Без HCL-изменения random_id хранится в state и не меняется. Принуди:

    bash
    terraform apply -auto-approve -replace=random_id.fn_suffix

    Plan покажет:

    # random_id.fn_suffix will be replaced (due to -replace)

    И каскадно, все ресурсы, которые от него зависят (Lambda, IAM-роль, потому что в имени есть random_id.fn_suffix.hex):

    # aws_iam_role.lambda will be destroyed
    # aws_iam_role.lambda will be created (new name)
    ...

    Apply пройдёт, всё пересоздастся с новым suffix. Это типичный кейс «протух pet name, хочу свежий».

    ✓ Регенерация random отработала каскадно.

    external: когда никакой провайдер не подходит

    Иногда нужно прочитать значение из источника, которого нет среди AWS data sources: git commit hash, secret из внутреннего хранилища, результат HTTP-запроса с auth.

    hcl
    terraform {
      required_providers {
        external = {
          source  = "hashicorp/external"
          version = "~> 2.3"
        }
      }
    }
    data "external" "build_info" {
      program = ["bash", "${path.module}/scripts/build-info.sh"]
    }
    resource "aws_lambda_function" "demo" {
      # ...
      tags = {
        GitCommit = data.external.build_info.result.commit
      }
    }

    Скрипт build-info.sh:

    bash
    #!/usr/bin/env bash
    set -euo pipefail
    commit=$(git -C / rev-parse HEAD 2>/dev/null || echo "unknown")
    jq -n --arg c "$commit" '{commit: $c}'

    Важно:

    • Скрипт вызывается на каждом plan, должен быть idempotent.
    • Все значения в результате, строки. Числа конвертируй через tonumber(data.external.x.result.count).
    • Скрипт работает с правами terraform-юзера. Это security-risk, не используй с непроверенным HCL.

    См. tf-archive-external-http про все три data-провайдера.

    • → Утилитарные провайдеры целиком
    • → archive, external, http

Что ты узнал

random, уникальные ID и пароли (sensitive в state): time, таймстампы и задержки. archive_file, упаковка файлов в zip для Lambda и Layers. external, выполнить произвольный скрипт, обменяться JSON. Все четыре HashiCorp-official, стабильные, без зависимости от AWS-API.

команды

  • terraform apply -replace=random_id.suffixпринудительная регенерация: каскад пересоздаст всё что зависит
  • terraform state show random_password.userпароль виден в state: sensitive только в выводе
  • terraform planexternal/archive вычисляются на каждом plan: учитывай

концепции

  • · random значения фиксируются в state: стабильны между apply
  • · archive_file: source_code_hash триггерит обновление Lambda при смене кода
  • · external: last resort: скрипт должен быть idempotent, отдавать только string-значения

← предыдущий

Гигиена HCL: fmt, validate, console

следующий →

Дебаг. TF_LOG, граф, чтение чужой ошибки

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