Модули Terraform: повторное использование кода на примере S3

В этой статье мы разберём, как создавать повторно используемые модули в Terraform на примере S3 Bucket (бакета). Модули помогают избежать копирования кода: один и тот же модуль можно подключить в нескольких средах с разными значениями переменных.
Ключевая идея: вынести повторяемую конфигурацию в каталог-модуль и подключать его из root-конфигураций с нужными параметрами.
Что понадобится
- Базовое понимание Terraform. (Определение: Terraform — инструмент для управления инфраструктурой как кодом.)
- Установленный Terraform на вашей машине.
- Аккаунт AWS (создайте при необходимости).
- Доступы IAM пользователя с access_key и secret_key. Храните их в безопасном месте и не публикуйте.
Важно: никогда не выкладывайте реальные секреты в репозитории. Используйте переменные окружения, secret manager или CI/CD секреты.
Что мы сделаем
- Напишем собственный модуль для S3.
- Подключим модуль из root-конфигурации и создадим бакет.
- Удалим ресурсы при помощи terraform destroy.
Структура проекта (рекомендуемая)
Рекомендуемая структура каталогов:
- modules/
- aws-s3/
- main.tf
- variables.tf
- outputs.tf (опционально)
- aws-s3/
- main.tf
- variables.tf
- terraform.tfvars
Создадим директорию модуля:
mkdir -p modules/aws-s3
Модуль: modules/aws-s3
Создайте файл modules/aws-s3/main.tf и вставьте следующий блок — это сам модуль, создающий S3 Bucket:
resource "aws_s3_bucket" "s3_bucket" {
bucket = var.bucket_name
acl = "public-read"
policy = <
Объяснение ключевых частей модуля:
- resource aws_s3_bucket — ресурс, создающий бакет.
- bucket = var.bucket_name — имя бакета задаётся через входную переменную.
- policy — JSON‑политика доступа, здесь простой пример публичного доступа для чтения объектов.
- website — блок конфигурации для статического сайта.
- tags — метки, передаваемые через переменные.
Переменные модуля
Создайте modules/aws-s3/variables.tf и объявите входные параметры модуля:
variable "bucket_name" {
description = "Name of the s3 bucket. Must be unique."
type = string
}
variable "tags" {
description = "Tags to set on the bucket."
type = map(string)
default = {}
}

Вы также можете добавить outputs.tf внутри модуля, например, чтобы экспортировать ARN бакета:
output "bucket_arn" {
value = aws_s3_bucket.s3_bucket.arn
description = "ARN созданного S3 бакета"
}Root-конфигурация: вызов модуля
В корне проекта создайте main.tf, который будет подключать модуль и содержать провайдера:
provider "aws" {
region = "${var.region}"
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
}
module "website_s3_bucket" {
source = "./modules/aws-s3"
bucket_name = "${var.bucket_name}"
tags = {
Terraform = "true"
Environment = "dev"
}
}

Пояснение:
- source — путь к модулю. Может быть локальным (как здесь) или указывать на реестр (registry) или VCS.
- Один и тот же source можно использовать в нескольких module-блоках с разными параметрами для создания нескольких бакетов.
Определение переменных в root
Создайте variables.tf в корне, где объявите переменные провайдера и имя бакета. Пример:
variable "access_key" {
description = "Access key to AWS console"
}
variable "secret_key" {
description = "Secret key to AWS console"
}
variable "region" {
description = "Region of AWS VPC"
}
variable "bucket_name" {
description = "(Required) Creates a unique bucket name"
type = "string"
default = "test-bucket-terraform-example"
}
Пример terraform.tfvars (пример значений)
Ниже — пример файла terraform.tfvars. Никогда не коммитьте реальные ключи. Используйте placeholder или безопасные механизмы хранения секретов:
region = "eu-west-3"
access_key = "YOUR_ACCESS_KEY"
secret_key = "YOUR_SECRET_KEY"Important: Замените YOUR_ACCESS_KEY и YOUR_SECRET_KEY на безопасно переданные в CI/CD или локальные переменные окружения. Не храните секреты в коде.
Команды: инициализация, план, применение, удаление
Перед выполнением убедитесь, что terraform доступен и credentials корректны.
- Инициализация плагинов провайдера:
terraform init
- Просмотр изменений (без применения):
terraform plan
- Применение плана (создание ресурсов):
terraform apply
- Удаление созданных ресурсов:
terraform destroy
После успешного terraform apply вы увидите сообщение об изменениях, например, 1 added, 0 destroyed. Проверьте в консоли AWS S3 — бакет должен появиться.
Безопасность и соответствие (Security & GDPR)
- Не храните секреты в репозитории. Используйте хранилище секретов (AWS Secrets Manager, HashiCorp Vault) или переменные окружения в CI.
- Минимизируйте права: создавайте IAM-пользователя с набором прав, нужным для создания S3 (principle of least privilege).
- По умолчанию не делайте бакет публичным, если в этом нет необходимости. В примере выше acl = “public-read” и политика делает объекты публичными — это подходит только для публичных статических сайтов.
- Для персональных данных применяйте шифрование на серверной стороне (SSE) и включайте версионирование и логирование доступа при необходимости.
Практические рекомендации и лучшие практики
- Используйте переменные и outputs для изоляции конфигурации.
- Добавьте validation в переменные (Terraform 0.13+), чтобы раннее поймать ошибки ввода.
- Поддерживайте версионирование модулей (например, тегируйте в Git) и используйте версии при подключении к remote‑registry.
- Тестируйте модули локально и в отдельной test‑среде перед production.
- Пишите README внутри modules/aws-s3 с описанием переменных, outputs и примеров использования.
Пример: подключение одного модуля дважды (staging и prod)
module "staging_bucket" {
source = "./modules/aws-s3"
bucket_name = "my-app-staging-bucket"
tags = { Environment = "staging" }
}
module "prod_bucket" {
source = "./modules/aws-s3"
bucket_name = "my-app-prod-bucket"
tags = { Environment = "production" }
}Когда модуль не подходит или ограничения
- Если требуется создание большого количества разнообразных ресурсов с разной логикой — целесообразно разделять на несколько специализированных модулей.
- Для ресурсов с крайне динамическими именами/параметрами возможно удобнее генерировать конфигурацию программно (через Terragrunt, Terraform Cloud/Workspaces или внешние скрипты).
Альтернативные подходы
- Terragrunt — слой над Terraform для DRY в управлении конфигурациями и переиспользования общих параметров.
- Использование модулей из Terraform Registry для стандартных шаблонов облачных ресурсов.
Мини‑методология разработки модулей (шаги)
- Сформулировать контракт: входные переменные и outputs.
- Реализовать resource-блоки и default‑значения.
- Добавить validation и документацию (README).
- Написать тесты/проверки в тестовой среде.
- Версионировать и публиковать (если публичный модуль).
Критерии приёмки
- Модуль корректно создаёт и удаляет ресурс без ошибок.
- Все обязательные переменные описаны и валидируются.
- Outputs возвращают полезные значения (ARN, имя, URL сайта).
- Документация включает пример использования и список переменных.
- Нет секретов в репозитории; доступы задаются безопасно.
Чек‑лист по ролям
- Разработчик:
- Создал модуль с документированными переменными и outputs.
- Добавил validation и примеры.
- DevOps/Инженер по безопасности:
- Проверил IAM-права и исключил лишние привилегии.
- Убедился в отсутствии секретов в коде.
- Тестировщик:
- Прогнал terraform plan/apply/destroy в тестовой среде.
- Проверил влияние на существующие ресурсы.
Сниппет: пример валидации переменной (Terraform >=0.13)
variable "bucket_name" {
description = "Name of S3 bucket"
type = string
validation {
condition = length(var.bucket_name) > 3
error_message = "bucket_name must be longer than 3 characters"
}
}Примеры тестовых случаев / acceptance
- При корректных input-значениях terraform apply создаёт бакет и outputs содержат ARN.
- При пустом или коротком имени — валидация предотвращает apply.
- При terraform destroy бакет удаляется и в AWS консоли ресурс исчезает.
Edge‑case gallery (типичные проблемы и их решения)
- Ошибка: bucket name already exists — S3 имена глобально уникальны. Решение: использовать префикс/суффикс с идентификатором окружения.
- Ошибка: AccessDenied при создании — проверьте права IAM.
- Проблемы с публичным доступом — учитывайте настройки блокировок публичного доступа в аккаунте AWS.
Decision flow (простое дерево принятия решения)
flowchart TD
A[Нужно ли переиспользовать конфигурацию?] -->|Да| B[Вынести в модуль]
A -->|Нет| C[Оставить в root]
B --> D{Требуется версия/публикация?}
D -->|Да| E[Версионировать и публиковать]
D -->|Нет| F[Использовать локальный модуль]Заключение
Мы создали простой модуль Terraform для S3, подключили его из root-конфигурации и рассмотрели важные вопросы безопасности, валидации и практик повторного использования. Модули упрощают поддержку и распространяют единый стандарт конфигурации по всем окружениям.
Короткое резюме
- Модуль инкапсулирует ресурс(ы) и интерфейс (переменные/outputs).
- source указывает на путь модуля (локально или в registry).
- Никогда не храните секреты в репозитории; применяйте минимальные права.
Спасибо за чтение. Если нужно, могу подготовить README.md для вашего модуля или добавить пример outputs/validation/CI‑pipeline.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента