тестирование IaC на Terraform, Test Kitchen и InSpec
Тестирование инфраструктуры как кода: надёжные релизы с Terraform и Kitchen-Terraform
9 минут
Ошибки в IaC по-прежнему дают простои и перерасход. В материале — слоистая стратегия тестов, пошаговый пример Kitchen-Terraform и InSpec для модуля AWS S3 и практики, чтобы проверки инфраструктуры оставались честными в CI.
Почему IaC ломается, если тестирование остаётся «по остаточному принципу»
Инфраструктура как код давно стала опорой DevOps, но ошибочные конфигурации по-прежнему ведут к простоям, дырам в безопасности и неожиданным счетам от облака. Привычные подходы к тестам часто относят инфраструктуру к второму плану по сравнению с приложением, поэтому команды упускают поведение, зависящее от среды, стыковку модулей и дрейф между объявленным в коде и фактически развёрнутым состоянием. Без системных проверок возникает та же логика «у меня работает», но уже в масштабе инфраструктуры: локально всё выглядело корректно, а в продакшене падает из-за версии провайдера, нюансов API или скрытых зависимостей.
Слой стратегии: модульные, интеграционные, сквозные проверки и дрейф
Относитесь к IaC как к критичному коду. «Модульный» уровень проверяет синтаксис и изоляцию ресурсов внутри модуля. Интеграционный прогон показывает, что модули согласованно работают в изолированном аккаунте или проекте. Сквозной сценарий поднимает полный стек во временной среде. Обнаружение дрейфа непрерывно сравнивает живое состояние с тем, что зафиксировано в репозитории. Kitchen-Terraform подключает Terraform к Test Kitchen: вы реально применяете конфигурацию и проверяете результат через InSpec на живом или имитируемом провайдере и получаете воспроизводимый цикл вместо разовых ручных проверок.
Пример структуры репозитория с модулем Terraform
Дерево ниже отражает типичное разделение: код модуля в корне, Gemfile для Test Kitchen, при необходимости корневой kitchen.yml, а интеграционные тесты лежат в test/integration/default вместе с controls и kitchen.yml для suite.
terraform-module-s3-bucket/
├── main.tf
├── variables.tf
├── outputs.tf
├── test/
│ ├── integration/
│ │ └── default/
│ │ ├── controls/
│ │ │ └── s3_bucket.rb
│ │ └── kitchen.yml
│ └── unit/
│ └── test_s3_bucket.rb
├── Gemfile
└── kitchen.ymlМодуль Terraform: корзина S3 с версионированием и SSE
Минимальный модуль соответствует актуальному разбиению в AWS provider (начиная с v4): в `aws_s3_bucket` остаются имя и теги, версионирование задаёт ресурс `aws_s3_bucket_versioning`, шифрование по умолчанию — отдельный `aws_s3_bucket_server_side_encryption_configuration` с SSE-AES256. Вложенные блоки `versioning` и `server_side_encryption_configuration` на самой корзине в новых версиях провайдера только для чтения; попытка управлять ими там приведёт к ошибке. Переменные по-прежнему можно передавать из Kitchen для уникальных одноразовых ресурсов.
variable "bucket_name" {
description = "Name of the S3 bucket"
type = string
}
variable "tags" {
description = "Tags to apply to the bucket"
type = map(string)
default = {}
}
resource "aws_s3_bucket" "this" {
bucket = var.bucket_name
tags = var.tags
}
resource "aws_s3_bucket_versioning" "this" {
bucket = aws_s3_bucket.this.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "this" {
bucket = aws_s3_bucket.this.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}Драйвер Kitchen-Terraform и верификатор
В suite заданы драйвер и provisioner Terraform с корнем в каталоге модуля, в variables передаётся имя корзины с меткой времени и теги, верификатор InSpec указывает на каталог интеграционных тестов. Платформа ubuntu-22.04 — распространённая метка в Kitchen, даже если сами проверки выполняются по API облака.
driver:
name: terraform
provisioner:
name: terraform
root_folder: ../..
variables:
bucket_name: "test-kitchen-s3-bucket-<%= Time.now.to_i %>"
tags:
Environment: test
Kitchen: verifies
verifier:
name: inspec
platforms:
- name: ubuntu-22.04
suites:
- name: default
verifier:
inspec_tests:
- test/integration/defaultControl InSpec для уже созданной корзины
После apply InSpec через AWS API проверяет, что корзина существует, включено версионирование и задана конфигурация шифрования. Падение теста блокирует продвижение изменений, потому что это сигнал о реальной ошибке конфигурации, а не о расхождении с моком.
control 's3-bucket-basics' do
impact 1.0
title 'Ensure S3 bucket has versioning and encryption'
describe aws_s3_bucket(bucket_name: input('bucket_name')) do
it { should exist }
its('versioning') { should eq true }
its('server_side_encryption_configuration') { should_not be_empty }
end
endСоздание, проверка, уничтожение
Цикл создаёт реальную корзину в AWS на короткоживущих учётных данных, прогоняет Terraform, выполняет InSpec и затем удаляет ресурсы. Это медленнее моков, но ловит поведение, специфичное для провайдера, которое видно только на живом API.
# Install dependencies
bundle install
# Create and converge the test instance
bundle exec kitchen create
# Run the verification
bundle exec kitchen verify
# Clean up
bundle exec kitchen destroyПрактики, из-за которых тесты IaC остаются полезными
Изолируйте среды через workspace или случайные суффиксы, чтобы параллельные прогоны не пересекались по именам. На интеграционном и сквозном уровнях по возможности используйте реальных провайдеров или высокоточные эмуляторы вроде LocalStack, оставив быстрые статические проверки ближе к началу пайплайна. Добавьте policy-as-code до apply — OPA с Conftest или Sentinel. Встройте набор в pull request и настройте кэширование под баланс скорости и глубины. Версионируйте модули по semver и публикуйте в частный реестр, чтобы потребители фиксировались на проверенных релизах. Отслеживайте флаки, вводите ограниченные повторы при транзиентных ошибках облака и отделяйте шум от регрессий. Контролируйте стоимость временных стендов. И наконец, документируйте назначение каждого control, чтобы набор тестов оставался понятным по мере роста команды.
Чтобы встроить такие проверки в поставку без наугад, согласуйте набор тестов с диагностикой из гайда по узким местам release-пайплайна.
Если тесты инфраструктуры ловят нестабильность, опирайтесь на наблюдаемость и культуру контролируемых отказов, как в статье про хаос-инжиниринг в DevOps.
