Terraform Modules с AI: Infrastructure-as-Code для стартапов без DevOps-инженера

Что такое Infrastructure as Code с AI-генерацией Terraform-модулей?

Infrastructure as Code с AI-генерацией Terraform-модулей — это практика использования структурированных LLM-промптов для создания валидных HCL-конфигураций, описывающих облачные ресурсы в версионируемом коде, что позволяет стартапам без выделенного DevOps-инженера разворачивать воспроизводимую инфраструктуру на AWS или GCP одной командой.

TL;DR

  • -Один структурированный промпт с провайдером, ресурсами, переменными, ограничениями безопасности, тегами и версиями генерирует Terraform-модуль, проходящий terraform validate и закрывающий большинство типичных сценариев.
  • -Секция безопасности в промпте обязательна — без неё модель выдаёт 0.0.0.0/0 в security groups и незашифрованное хранилище по умолчанию.
  • -Remote state в S3 (AWS) или GCS (GCP) — минимум для командного использования; state-файл содержит секреты в открытом виде и никогда не должен попадать в git.
  • -Три уровня валидации — terraform validate, tflint, checkov — ловят случаи, когда AI генерирует синтаксически корректный, но функционально сломанный или небезопасный HCL.
  • -Ошибки AI-генерации предсказуемы: циклические зависимости security groups, отсутствующие depends_on для IAM attachments, wildcard-права, отсутствие lifecycle rules — добавляйте превентивные инструкции в промпт.

Каждый ресурс, созданный через веб-консоль облачного провайдера, невозможно воспроизвести, откатить или передать новому разработчику. Когда команда вырастает до пяти человек, инфраструктурный долг начинает тормозить релизы.

Terraform решает эту проблему: вся инфраструктура описана в коде, хранится в Git, применяется одной командой. Но у стартапов нет DevOps-инженера, который напишет модули с нуля. AI-модели закрывают этот разрыв. Один структурированный промпт генерирует Terraform-модуль, который проходит terraform validate и закрывает большинство типичных сценариев.

В этой статье: от нуля до рабочей инфраструктуры. Промпты для генерации модулей, примеры для AWS и GCP, управление state, безопасность и паттерны, которые предотвращают типичные ошибки новичков.

Terraform за 10 минут: минимум для старта

Terraform оперирует тремя концепциями: провайдеры, ресурсы и state.

Провайдер подключает Terraform к облачной платформе. AWS, GCP, Azure, Cloudflare — для каждого свой провайдер. Провайдер знает API платформы и транслирует HCL-код в API-вызовы.

Ресурс описывает один объект инфраструктуры: виртуальную машину, базу данных, DNS-запись, S3-бакет. Ресурсы связаны между собой через ссылки: сервер использует подсеть, подсеть принадлежит VPC.

State хранит текущее состояние инфраструктуры. Terraform сравнивает state с описанием в коде и вычисляет diff: что создать, что изменить, что удалить. Без state Terraform не знает, какие ресурсы уже существуют.

Минимальная структура проекта:

infrastructure/
├── main.tf          # Ресурсы
├── variables.tf     # Входные параметры
├── outputs.tf       # Выходные значения
├── providers.tf     # Настройка провайдеров
└── terraform.tfvars # Значения переменных (не коммитить секреты)

Рабочий цикл состоит из четырёх команд:

terraform init      # Скачивает провайдеры
terraform plan      # Показывает что изменится
terraform apply     # Применяет изменения
terraform destroy   # Удаляет всё (осторожно)

terraform plan — самая важная команда. Она показывает diff между кодом и реальной инфраструктурой до того, как что-то изменится. Всегда проверяйте plan перед apply.

Модули: переиспользуемые блоки инфраструктуры

Модуль в Terraform — это директория с .tf-файлами, которую можно вызвать из другого кода с параметрами. Тот же принцип, что и функция в программировании: входные параметры, логика, выходные значения.

Структура модуля:

modules/
└── vpc/
    ├── main.tf        # Ресурсы VPC, подсети, роутинг
    ├── variables.tf   # Параметры: CIDR, количество AZ, теги
    └── outputs.tf     # VPC ID, subnet IDs

Вызов модуля из корневого конфига:

module "network" {
  source = "./modules/vpc"

  cidr_block         = "10.0.0.0/16"
  availability_zones = ["us-east-1a", "us-east-1b"]
  project_name       = "myapp"
  environment        = "production"
}

Модули решают три задачи сразу. Модуль описывается один раз и вызывается для каждого окружения — dev, staging, production — с разными параметрами. Он инкапсулирует сложность: вызывающий код передаёт пять параметров вместо описания двадцати связанных ресурсов. И его можно протестировать отдельно от остальной инфраструктуры.

Промпты для генерации Terraform-модулей

AI-модель генерирует Terraform-код тем точнее, чем конкретнее описан контекст. Промпт должен содержать шесть элементов:

  1. Облачный провайдер и регион — AWS us-east-1, GCP europe-west1
  2. Что создать — конкретные ресурсы и связи между ними
  3. Параметризация — что должно быть переменной, а что захардкожено
  4. Безопасность — сетевые ограничения, IAM-роли, шифрование
  5. Теги и именование — конвенция имён, обязательные теги
  6. Ограничения — версия Terraform, версия провайдера, запрещённые ресурсы

Базовый шаблон промпта:

Сгенерируй Terraform-модуль для [облачный провайдер].

Ресурсы:
- [список ресурсов с ключевыми параметрами]

Требования:
- Terraform >= 1.5, провайдер [имя] >= [версия]
- Все ресурсы в [регион]
- Переменные: [что параметризовать]
- Выходы: [что экспортировать]
- Security: [конкретные ограничения]
- Теги: project, environment, managed_by = "terraform"

Структура:
- main.tf, variables.tf, outputs.tf, versions.tf
- Описания для каждой переменной
- Валидация для критичных переменных (CIDR, имена)

Не используй: [запрещённые паттерны]

Промпт без секции безопасности выдаёт ресурсы с 0.0.0.0/0 в security groups и без шифрования. Промпт без ограничений на версии выдаёт код, который сломается при обновлении провайдера. Каждая секция предотвращает конкретную категорию ошибок.

Пример: AWS VPC + ECS Fargate

Промпт для генерации полного стека приложения на AWS:

Сгенерируй Terraform-модуль: AWS VPC с ECS Fargate.

Ресурсы:
- VPC с 2 public и 2 private подсетями в разных AZ
- NAT Gateway (один, для экономии)
- ECS Cluster с Fargate capacity provider
- ECS Service + Task Definition для контейнера
- Application Load Balancer в public подсетях
- Security Groups: ALB принимает 80/443, ECS принимает только от ALB
- CloudWatch Log Group для контейнера

Переменные:
- vpc_cidr (default "10.0.0.0/16", с валидацией CIDR формата)
- container_image (string, без default)
- container_port (number, default 8080)
- cpu, memory (number, defaults 256/512)
- desired_count (number, default 2)
- environment (string, validation: dev|staging|production)
- project_name (string)

Выходы:
- vpc_id, public_subnet_ids, private_subnet_ids
- alb_dns_name, ecs_cluster_arn, ecs_service_name

Terraform >= 1.5, AWS provider >= 5.0.
Все ресурсы в переменной aws_region (default us-east-1).
Теги: Project, Environment, ManagedBy = "terraform".

Результат содержит 150–200 строк HCL-кода. AI-модель создаёт правильные связи между ресурсами: ECS task definition ссылается на log group, security group ECS-сервиса разрешает трафик только от security group ALB, private подсети используют NAT Gateway для исходящего трафика.

Ключевые моменты, которые нужно проверить в сгенерированном коде:

# Security group ECS — трафик только от ALB
resource "aws_security_group_rule" "ecs_ingress" {
  type                     = "ingress"
  from_port                = var.container_port
  to_port                  = var.container_port
  protocol                 = "tcp"
  source_security_group_id = aws_security_group.alb.id
  security_group_id        = aws_security_group.ecs.id
}

# Task definition — лимиты ресурсов заданы явно
resource "aws_ecs_task_definition" "app" {
  family                   = "${var.project_name}-${var.environment}"
  requires_compatibilities = ["FARGATE"]
  network_mode             = "awsvpc"
  cpu                      = var.cpu
  memory                   = var.memory
  execution_role_arn       = aws_iam_role.ecs_execution.arn

  container_definitions = jsonencode([{
    name      = var.project_name
    image     = var.container_image
    essential = true
    portMappings = [{
      containerPort = var.container_port
      protocol      = "tcp"
    }]
    logConfiguration = {
      logDriver = "awslogs"
      options = {
        "awslogs-group"         = aws_cloudwatch_log_group.app.name
        "awslogs-region"        = var.aws_region
        "awslogs-stream-prefix" = "ecs"
      }
    }
  }])
}

Если AI-модель пропустила execution_role_arn в task definition или не создала IAM-роль с policy AmazonECSTaskExecutionRolePolicy, контейнер не запустится. Это частая ошибка генерации, которую нужно отлавливать на этапе review.

Пример: GCP Cloud Run + Cloud SQL

Тот же подход для Google Cloud:

Сгенерируй Terraform-модуль: GCP Cloud Run + Cloud SQL PostgreSQL.

Ресурсы:
- VPC с private subnet
- Cloud SQL PostgreSQL 15 (db-f1-micro для dev, db-custom для prod)
- Private IP для Cloud SQL через VPC peering
- Cloud Run service с подключением к SQL через VPC connector
- Serverless VPC Connector
- Secret Manager для database password
- IAM bindings: Cloud Run SA с ролями cloudsql.client, secretmanager.secretAccessor

Переменные:
- project_id (string)
- region (default "europe-west1")
- database_name (string)
- cloud_run_image (string)
- cloud_run_cpu, cloud_run_memory (defaults "1", "512Mi")
- min_instances, max_instances (defaults 0, 10)
- environment (validation: dev|staging|production)

Выходы:
- cloud_run_url, cloud_sql_connection_name
- vpc_connector_id, database_ip

Terraform >= 1.5, Google provider >= 5.0.
Включить необходимые API через google_project_service.

GCP требует явного включения API (compute.googleapis.com, run.googleapis.com, sqladmin.googleapis.com). AI-модели часто пропускают этот шаг. Добавление строки «Включить необходимые API через google_project_service» в промпт заставляет модель генерировать блоки:

resource "google_project_service" "required" {
  for_each = toset([
    "compute.googleapis.com",
    "run.googleapis.com",
    "sqladmin.googleapis.com",
    "vpcaccess.googleapis.com",
    "secretmanager.googleapis.com",
  ])

  project = var.project_id
  service = each.value

  disable_dependent_services = false
  disable_on_destroy         = false
}

disable_on_destroy = false критичен. Без него terraform destroy отключит API, что может сломать другие ресурсы в проекте, не управляемые этим Terraform-кодом.

Управление state: remote backend

По умолчанию Terraform хранит state в локальном файле terraform.tfstate. Для команды это не работает: state должен быть доступен всем и защищён от параллельных изменений.

Remote backend для AWS (S3 с нативной блокировкой):

terraform {
  backend "s3" {
    bucket       = "mycompany-terraform-state"
    key          = "production/infrastructure.tfstate"
    region       = "us-east-1"
    encrypt      = true
    use_lockfile = true  # нативная блокировка S3, Terraform 1.11+
  }
}

Remote backend для GCP (GCS):

terraform {
  backend "gcs" {
    bucket = "mycompany-terraform-state"
    prefix = "production/infrastructure"
  }
}

Промпт для генерации backend-инфраструктуры:

Сгенерируй Terraform-код для создания remote backend.

AWS вариант:
- S3 bucket с versioning и server-side encryption (AES256)
- Bucket policy: запретить удаление объектов
- Lifecycle rule: хранить noncurrent versions 90 дней

Блокировка state — нативная в S3 через use_lockfile, отдельная DynamoDB-таблица не нужна.
Не использовать backend block в этом коде (chicken-and-egg problem).
State этого кода хранится локально.

Важный нюанс: инфраструктура для хранения state создаётся отдельным Terraform-проектом с локальным state. Это решает проблему курицы и яйца. AI-модели иногда добавляют backend block в код, который создаёт сам бакет для state. Промпт с явным запретом предотвращает эту ошибку.

State: безопасность и операции

State-файл содержит секреты. Пароли баз данных, ключи API, приватные IP-адреса — всё попадает в state в открытом виде. Три правила:

Шифрование. S3 backend поддерживает encrypt = true. GCS шифрует объекты по умолчанию. Для дополнительной защиты используйте KMS-ключ вместо managed encryption.

Доступ. Ограничьте доступ к бакету со state. Только CI/CD pipeline и администраторы. Terraform Cloud и HCP Terraform решают это из коробки.

Блокировка. S3 блокирует state нативно через use_lockfile = true (Terraform 1.11+). DynamoDB-локи, которые раньше были стандартом, помечены deprecated и будут удалены в будущих версиях. GCS блокирует по умолчанию. Без блокировки два параллельных terraform apply повредят state-файл.

Операции со state, которые понадобятся:

# Посмотреть текущие ресурсы в state
terraform state list

# Переместить ресурс (при рефакторинге модулей)
terraform state mv 'module.old.aws_instance.web' 'module.new.aws_instance.web'

# Импортировать существующий ресурс (уже создан вручную)
terraform import 'aws_s3_bucket.data' 'my-existing-bucket'

# Убрать ресурс из управления (без удаления)
terraform state rm 'aws_instance.temporary'

terraform import особенно полезен для стартапов, которые уже создали инфраструктуру через консоль. Вместо пересоздания ресурсов можно импортировать существующие в state и дальше управлять через код.

Промпты для итеративного улучшения модулей

Первая версия модуля от AI закрывает базовые потребности. Следующие промпты добавляют production-hardening:

Добавить мониторинг:

К существующему модулю ECS Fargate добавь:
- CloudWatch alarms: CPU > 80%, Memory > 80%, UnhealthyHostCount > 0
- SNS Topic для нотификаций (email подписка через переменную)
- Dashboard с графиками CPU, Memory, Request Count, Response Time

Alarm actions указывают на SNS topic.
Не изменяй существующие ресурсы.

Добавить autoscaling:

К ECS Service добавь Application Auto Scaling:
- Target tracking по CPU utilization (target 70%)
- Target tracking по Memory utilization (target 75%)
- Scale-in cooldown 300s, scale-out cooldown 60s
- Min capacity из переменной, max capacity из переменной

Используй aws_appautoscaling_target и aws_appautoscaling_policy.

Добавить DNS и HTTPS:

К существующему ALB добавь:
- Route53 record (A alias) для домена из переменной
- ACM certificate с DNS validation
- HTTPS listener (443) на ALB
- Redirect HTTP → HTTPS
- Route53 validation records для ACM

Переменные: domain_name, route53_zone_id.

Каждый промпт расширяет модуль одной функцией. Это проще для review и отладки, чем генерировать всё сразу. AI-модель лучше справляется с инкрементальными задачами, когда контекст ограничен конкретным изменением.

Структура проекта для нескольких окружений

Стартап начинает с одного окружения, но быстро дорастает до трёх: dev, staging, production. Terraform-модули позволяют переиспользовать код между окружениями.

Рекомендуемая структура:

infrastructure/
├── modules/
│   ├── networking/    # VPC, подсети, NAT
│   ├── compute/       # ECS/Cloud Run, task definitions
│   ├── database/      # RDS/Cloud SQL
│   └── monitoring/    # CloudWatch/Cloud Monitoring
├── environments/
│   ├── dev/
│   │   ├── main.tf        # Вызовы модулей
│   │   ├── variables.tf
│   │   ├── terraform.tfvars
│   │   └── backend.tf
│   ├── staging/
│   │   └── ...
│   └── production/
│       └── ...
└── global/
    ├── iam/           # IAM roles, policies
    └── dns/           # Route53 zones

Каждое окружение вызывает те же модули с разными параметрами:

# environments/dev/main.tf
module "network" {
  source = "../../modules/networking"

  cidr_block    = "10.0.0.0/16"
  nat_gateway   = false  # Экономия в dev
  project_name  = "myapp"
  environment   = "dev"
}

module "compute" {
  source = "../../modules/compute"

  vpc_id            = module.network.vpc_id
  subnet_ids        = module.network.private_subnet_ids
  container_image   = "myapp:latest"
  desired_count     = 1       # Минимум в dev
  cpu               = 256
  memory            = 512
  environment       = "dev"
}
# environments/production/main.tf
module "network" {
  source = "../../modules/networking"

  cidr_block    = "10.1.0.0/16"
  nat_gateway   = true   # Обязательно в production
  project_name  = "myapp"
  environment   = "production"
}

module "compute" {
  source = "../../modules/compute"

  vpc_id            = module.network.vpc_id
  subnet_ids        = module.network.private_subnet_ids
  container_image   = "myapp:v1.2.3"
  desired_count     = 3       # Redundancy
  cpu               = 1024
  memory            = 2048
  environment       = "production"
}

Dev обходится без NAT Gateway ($32/мес) и запускает один контейнер. Production включает NAT, три контейнера и больше ресурсов. Тот же код, разные параметры.

Валидация сгенерированного кода

AI-модель в большинстве случаев генерирует синтаксически корректный HCL. Оставшиеся случаи ловятся на этапе валидации. Три уровня проверки:

Уровень 1: Terraform CLI

terraform init
terraform validate
terraform plan

validate проверяет синтаксис и ссылки между ресурсами. plan проверяет, что провайдер принимает указанные параметры. Если plan выдаёт ошибку, скопируйте сообщение обратно в AI-модель с промптом «Исправь эту ошибку в Terraform-коде» и приложите полный файл.

Уровень 2: tflint

# Установка
brew install tflint    # macOS
tflint --init          # Скачать плагины

# Запуск
tflint --recursive

tflint находит ошибки, которые terraform validate пропускает: устаревшие типы инстансов, несуществующие AMI, неоптимальные конфигурации. Промпт для исправления: «tflint выдаёт предупреждения [список]. Исправь модуль, сохраняя функциональность.»

Уровень 3: checkov (безопасность)

pip install checkov
checkov -d .

checkov проверяет конфигурацию на соответствие best practices безопасности: шифрование включено, публичный доступ закрыт, логирование настроено. Типичные findings после AI-генерации:

  • S3 bucket без block_public_access
  • Security group с 0.0.0.0/0 на ingress
  • RDS без storage_encrypted = true
  • CloudWatch log group без retention_in_days

Каждый finding из checkov превращается в промпт для AI: «Добавь в S3 bucket ресурс aws_s3_bucket_public_access_block с block_public_acls = true, block_public_policy = true, ignore_public_acls = true, restrict_public_buckets = true.»

Best practices для Terraform с AI

Версии провайдеров. Всегда фиксируйте версии в versions.tf:

terraform {
  required_version = ">= 1.5"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

~> 5.0 разрешает 5.x, но не 6.0. Без фиксации terraform init может скачать новую мажорную версию провайдера, которая сломает существующий код.

Именование. Используйте единую конвенцию. Промпт «Все имена ресурсов в формате {project}-{environment}-{resource}» заставляет AI-модель генерировать консистентные имена вместо произвольных.

Не хардкодьте AMI и machine types. Используйте data sources:

data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

Захардкоженный AMI ID привязан к конкретному региону и устаревает через месяцы. Data source всегда выбирает актуальный образ.

Используйте terraform plan в CI/CD. Каждый pull request с изменениями инфраструктуры должен запускать terraform plan и показывать diff в комментарии. Подробный гайд по настройке CI/CD-пайплайна для Terraform есть в статье про генерацию CI/CD пайплайнов.

Никогда не коммитьте tfvars с секретами. .gitignore должен содержать:

*.tfvars
!terraform.tfvars.example
.terraform/
*.tfstate
*.tfstate.backup

Секреты передавайте через переменные окружения (TF_VAR_database_password) или через secret manager провайдера.

Разделяйте state по контурам. Один state-файл на окружение. Dev и production никогда не живут в одном state. Ошибка в dev не должна иметь возможность затронуть production-ресурсы.

Типичные ошибки AI-генерации и как их предотвращать

AI-модели допускают предсказуемые ошибки в Terraform-коде. Зная паттерны, можно добавлять превентивные инструкции в промпт.

Циклические зависимости. AI создаёт security group A, которая ссылается на security group B, которая ссылается на A. Terraform выдаёт ошибку цикла. Решение: выносите правила в отдельные ресурсы вместо inline ingress/egress блоков — в AWS-провайдере 5.0+ это aws_vpc_security_group_ingress_rule и aws_vpc_security_group_egress_rule (по одному правилу на ресурс; старый aws_security_group_rule ещё работает, но новые ресурсы предпочтительнее). Добавьте в промпт: «Security group rules через отдельные ресурсы, не inline.»

Забытые depends_on. Некоторые зависимости между ресурсами Terraform не выводит автоматически. Пример: IAM role policy attachment должна быть создана до ECS task, но Terraform не видит эту связь через jsonencode. Добавьте: «Используй depends_on для неявных зависимостей: IAM policy attachments → compute resources.»

Избыточные permissions. AI-модель часто выдаёт Action: "*" и Resource: "*" в IAM policies. Добавьте в промпт: «IAM policies с минимальными правами. Конкретные Actions и Resources. Никаких wildcards, кроме случаев, где это единственный вариант.»

Отсутствие lifecycle rules. AI создаёт ресурсы без prevent_destroy для критичных данных и без create_before_destroy для ресурсов с zero-downtime требованием:

resource "aws_db_instance" "main" {
  # ...
  lifecycle {
    prevent_destroy = true
  }
}

resource "aws_ecs_service" "app" {
  # ...
  lifecycle {
    create_before_destroy = true
  }
}

Добавьте в промпт: «lifecycle prevent_destroy для баз данных и state buckets. create_before_destroy для compute-ресурсов.»

Миграция с ручной инфраструктуры на Terraform

Стартап с существующей инфраструктурой в облаке может перейти на Terraform без пересоздания ресурсов. Алгоритм:

  1. Опишите существующие ресурсы в Terraform-коде (AI-модель поможет по описанию из консоли)
  2. Импортируйте каждый ресурс: terraform import aws_instance.web i-1234567890abcdef0
  3. Запустите terraform plan. Diff должен быть пустым
  4. Если plan показывает изменения, скорректируйте код до полного совпадения с реальностью
  5. Теперь ресурсами управляет Terraform

Промпт для шага 1:

У меня есть EC2 инстанс со следующими параметрами:
- Instance type: t3.medium
- AMI: ami-0abcdef1234567890
- VPC: vpc-12345, Subnet: subnet-67890
- Security groups: sg-11111, sg-22222
- EBS: 50GB gp3, encrypted
- Tags: Name=web-server, Environment=production

Сгенерируй Terraform resource block, который точно описывает
этот инстанс. Включи все параметры, которые Terraform отслеживает.
Не пропускай default values, если они отличаются от реальной конфигурации.

Для массовой миграции существует terraformer — инструмент, который автоматически генерирует Terraform-код из существующей инфраструктуры. Но сгенерированный код требует рефакторинга: он плоский, без модулей, без переменных. AI-модель отлично справляется с рефакторингом terraformer-вывода в чистую модульную структуру.

Что дальше

Terraform-модули с AI закрывают большую часть потребностей стартапа в управлении инфраструктурой. Следующие шаги зависят от масштаба:

До 10 разработчиков: локальный state в S3/GCS, ручной terraform apply, code review для .tf-файлов. Этого достаточно.

10–30 разработчиков: Terraform Cloud или Atlantis для автоматического plan на PR и apply на merge. Sentinel или OPA для policy-as-code.

30+ разработчиков: Platform team, внутренний registry модулей, self-service через Internal Developer Platform.

Для каждого этапа AI-модели генерируют необходимые конфигурации. Подход из этой статьи масштабируется вместе с командой: меняются только промпты и уровень абстракции модулей.

Настройка CI/CD для автоматического apply описана в гайде по генерации пайплайнов. Паттерн circuit breaker для защиты инфраструктурных API-вызовов от каскадных отказов разобран в статье про resilience в edge functions.


Нужна помощь с Infrastructure-as-Code? Я помогаю стартапам внедрять AI-решения и строить продукты — belov.works.

FAQ

Как безопасно рефакторить существующий модуль, не сломав production-инфраструктуру?

Ключ — манипуляции со state до изменений кода. Перед реструктуризацией модуля выполняйте terraform state mv, чтобы переместить ресурсы на новые логические адреса в state — это сообщает Terraform, что ресурс уже существует по новому пути, а не является операцией «удалить и создать». После каждого перемещения запускайте terraform plan и убеждайтесь, что diff не содержит деструктивных изменений. Для сложных рефакторингов с большим числом ресурсов сначала отработайте процесс на non-production окружении, сравните plan до и после, и только затем применяйте те же операции к production.

Как передавать секреты, нужные Terraform при apply, не сохраняя их в state?

State-файл Terraform хранит атрибуты ресурсов в открытом виде, включая чувствительные значения. Практическое решение: никогда не передавать реальные значения секретов через Terraform-переменные — вместо этого использовать нативные ссылки провайдера. Для AWS: хранить учётные данные в Secrets Manager и ссылаться на них через data source aws_secretsmanager_secret_version, который подставляет значение только в момент создания ресурса. Цель — чтобы в terraform.tfstate оставалась только ссылка (ARN, путь), а не само значение секрета.

Как AI-модели справляются с обновлениями версий Terraform-провайдеров и что требует обязательной ручной проверки?

AI генерирует синтаксически корректный код для той версии провайдера, на которой обучена, но API провайдеров меняется между мажорными версиями: аргументы ресурсов переименовываются, устаревают или удаляются. При обновлении провайдеров используйте terraform providers lock для фиксации новой версии и запускайте terraform plan для обнаружения ошибок — вставляйте эти ошибки обратно в модель с полным блоком ресурса и выдержкой из changelog провайдера. Ручная проверка обязательна для IAM-политик (AI склонен к избыточным правам), lifecycle rules (особенно prevent_destroy) и ресурсов, управляющих настройками шифрования.