Политики Terraform предназначены для проверки инфраструктуры перед применением изменений. С их помощью можно ограничить типы виртуальных машин, потребовать тег владельца или запретить удаление критичных ресурсов.
В этой статье под политиками понимается Policy as Code — проверка инфраструктурных изменений. IAM policies и политики S3 управляют доступом в AWS и решают другую задачу.
Для чего это нужно: пример из работы
Представим, что нужно создать виртуальную машину для тестового сайта. Для этой задачи команда разрешила использовать небольшие EC2 типов t3.micro и t3.small. Разработчик копирует конфигурацию из другого проекта и оставляет в ней более крупный тип машины:
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = "m5.4xlarge"
tags = {
Owner = "platform"
}
}
С точки зрения Terraform такой тип машины может быть допустимым. Проверка terraform validate не обнаружит нарушение внутренних правил команды, а успешный terraform plan покажет создание ресурса. Без дополнительной проверки ошибку придётся заметить при просмотре плана вручную.
Добавим политику: для тестового окружения разрешены только t3.micro и t3.small. Теперь перед применением изменений проверка обнаружит m5.4xlarge и остановит процесс. Разработчик исправит значение:
instance_type = "t3.micro"
После исправления нужно сформировать новый план и проверить его заново. Если остальные правила выполнены, изменения можно применять. Так политика помогает избежать лишних расходов из-за случайно скопированного параметра. Пример Sentinel ниже реализует именно такое ограничение; назначать его следует workspace тестового окружения.
Другая задача — определить, кто отвечает за машину. Через месяц в облаке может оказаться несколько десятков ресурсов, и без тега Owner будет сложно понять, кому задать вопрос об их назначении. Политика OPA из следующего примера потребует заполнить этот тег до создания машины. Она проверяет наличие значения, но не подтверждает, что указанный владелец действительно существует: для этого понадобится дополнительное правило.
Кто проверяет правила
Terraform сам по себе не знает, какие типы машин разрешены в вашей команде. Чтобы проверить такое правило, нужна отдельная программа — движок политик. Ей передают сведения об инфраструктуре и написанные нами условия. Программа проверяет условия и возвращает результат: правило выполнено или найдено нарушение.
В статье рассмотрим два инструмента:
- Sentinel — инструмент HashiCorp для написания и выполнения политик. Правила пишутся на языке Sentinel. В нашем примере их автоматически запускает платформа HCP Terraform или Terraform Enterprise.
- OPA (Open Policy Agent) — отдельная программа с открытым исходным кодом для проверки правил. Правила пишутся на языке Rego. В нашем примере мы сами запустим OPA командой в терминале и передадим ей Terraform-план.
Для начала достаточно выбрать один вариант. Если Terraform запускается локально или в собственном CI, пример с OPA можно использовать без платформы HashiCorp. Если команда работает через HCP Terraform или Terraform Enterprise, рассмотренный пример Sentinel показывает проверку внутри этой платформы.
Нужно ли устанавливать движки отдельно
Ни Sentinel, ни OPA не входят в стандартную поставку Terraform CLI. После установки команды terraform команды opa и sentinel сами не появятся. Это отдельные инструменты, которые устанавливаются отдельно.
| Инструмент | Может ли обычный пользователь начать пользоваться |
|---|---|
| OPA | Да. Можно скачать программу, написать правило и проверить JSON-план на своём компьютере без аккаунта HCP Terraform |
| Sentinel CLI | Да, для разработки и локальной проверки правил. Для примера с tfplan/v2 нужно также подготовить данные импорта, например mocks — тестовые данные, имитирующие план |
| Автоматическая проверка Sentinel в HCP Terraform / Terraform Enterprise | Terraform запускается через эту систему, а она сама вызывает Sentinel после plan и блокирует apply при нарушении обязательной политики. Нужны доступ к системе и права на настройку политик |
Что означает автоматическая проверка в HCP Terraform или Terraform Enterprise? В этом варианте запуском Terraform управляет отдельная система. HCP Terraform — облачный сервис HashiCorp. Terraform Enterprise организация устанавливает на своих серверах. Пользователь отправляет конфигурацию и запускает выполнение через эту систему, например из интерфейса или через подключённый Git-репозиторий.
Администратор подключает к системе правила Sentinel и указывает, для каких рабочих пространств их выполнять. Дальше система сама организует последовательность:
Пользователь отправил изменения
↓
Система выполнила terraform plan
↓
Система запустила Sentinel и передала ему данные плана
↓
Обязательная политика нарушена → система не разрешает apply
Политики пройдены → можно продолжить запуск с учётом согласований
То есть Sentinel здесь является частью управляемого процесса запуска Terraform. Пользователю не требуется вручную вызывать команду sentinel для каждой проверки. Если же выполнять terraform apply напрямую на своём компьютере, эта проверка сама по себе не запустится. Чтобы обязательные правила нельзя было обойти, команда должна ограничить прямой доступ к изменению инфраструктуры и выполнять изменения через настроенную систему.
Для первого знакомства с самостоятельной проверкой плана воспользуемся OPA. Скачайте подходящий для своей системы исполняемый файл по официальной инструкции установки OPA и добавьте его каталог в PATH — список каталогов, в которых оболочка ищет команды. После установки проверьте:
opa version
Теперь можно запускать команды из раздела с OPA ниже. Отдельный сервер OPA для этих примеров не нужен: программа прочитает локальные файлы и завершится после проверки. Хранение бинарного файла в своём пользовательском каталоге позволяет обойтись без установки в системные каталоги и прав администратора.
Sentinel CLI тоже можно установить отдельно. Он позволяет разрабатывать и тестировать правила локально, но его установка не добавляет проверку в команды terraform plan и terraform apply. Кроме того, источник tfplan/v2 в локальном тесте нужно обеспечить данными: одного Terraform-файла рядом с политикой недостаточно. Назначение CLI описано в документации Sentinel.
Где выполняется проверка
Рассмотрим, на каком этапе выполняется проверка политик:
terraform init → terraform validate → terraform plan
↓
проверка политик
↓
terraform apply
terraform validate проверяет корректность конфигурации, но не знает правил вашей организации. Политика анализирует план и решает, допустимо ли изменение. HCP Terraform — облачный сервис HashiCorp. Он предназначен для запуска Terraform и совместной работы с инфраструктурой. Terraform Enterprise — платформа, которую организация разворачивает у себя. Они могут автоматически запускать Sentinel и OPA между планированием и применением изменений.
CI — система автоматического выполнения команд проекта, например после отправки изменений в Git. В собственном CI мы можем добавить отдельную команду запуска OPA и остановить дальнейшее выполнение, если проверка не прошла.
Проверка плана видит изменения из модулей и итоговые значения, известные Terraform на этом этапе. Значения, вычисляемые только при применении, требуют отдельного решения: запретить неопределённость, вынести проверку на более поздний этап или явно разрешить исключение.
Доступны ли политики без HCP Terraform
Terraform CLI — программа terraform, которую мы запускаем в терминале. При её использовании проверку политик можно организовать самостоятельно. Встроенного запуска policy sets Sentinel и OPA между plan и apply в CLI нет: такую интеграцию предоставляют HCP Terraform и Terraform Enterprise.
Рассмотрим различия:
| Вариант | Как выполняется проверка |
|---|---|
| Terraform CLI и OPA | OPA запускается отдельно, локально или в CI, и проверяет JSON-план |
| HCP Terraform / Terraform Enterprise | Платформа запускает назначенные workspace наборы политик |
| Terraform CLI и файл Sentinel | Само наличие файла не запускает проверку и не блокирует apply |
Таким образом, пример с OPA ниже можно использовать без HCP Terraform и Terraform Enterprise. OPA — отдельный открытый движок политик. Потребуется самостоятельно настроить запуск проверки и остановку pipeline при нарушениях. Пользователь, имеющий права на прямой terraform apply, сможет обойти такую проверку, если доступ к применению не ограничен процессом CI.
Под «опенсорсной версией» часто подразумевают бесплатный Terraform CLI. Для современных выпусков точнее говорить о Community Edition: HashiCorp перевела новые выпуски Terraform на Business Source License (BSL), поэтому бесплатность CLI и открытая лицензия — разные вопросы. Подробнее об изменении лицензии — в пояснении HashiCorp.
Интеграцию платформ с политиками описывает документация HashiCorp, а самостоятельную проверку JSON-плана — руководство OPA.
Sentinel: ограничиваем типы виртуальных машин
Начнём с варианта, в котором проверку запускает платформа HashiCorp. EC2 — сервис виртуальных машин AWS, а aws_instance — название Terraform-ресурса для такой машины. Рассмотрим пример: разрешим создание EC2 только с типами t3.micro и t3.small. Чтобы Sentinel получил доступ к плану Terraform, подключим tfplan/v2. Это предоставляемый платформой источник данных: через него правило читает ресурсы и их запланированные значения.
Сохраним правило в файл allowed-instance-types.sentinel:
import "tfplan/v2" as tfplan
allowed_types = ["t3.micro", "t3.small"]
instances = filter tfplan.resource_changes as _, rc {
rc.mode is "managed" and
rc.type is "aws_instance" and
rc.change.actions is not ["delete"]
}
main = rule {
all instances as _, rc {
(rc.change.after.instance_type else "") in allowed_types
}
}
Здесь allowed_types содержит разрешённые типы машин, а instances — выбранные из плана ресурсы EC2. Правило main проверяет тип каждой машины, которая останется после применения, включая неизменённые ресурсы и замены. Чистое удаление пропускается. Если тип отсутствует или неизвестен, подстановка пустой строки приводит к отказу. Для неизвестного значения здесь намеренно выбрана строгая проверка.
Одного файла с условием недостаточно: платформе нужно указать, какое правило запускать и что делать при нарушении. Для этого создадим файл настроек sentinel.hcl:
policy "allowed-instance-types" {
source = "./allowed-instance-types.sentinel"
enforcement_level = "hard-mandatory"
}
Здесь source задаёт путь к файлу правила, а enforcement_level определяет реакцию на нарушение. Значение hard-mandatory означает обязательную проверку: при отказе применять план нельзя.
Теперь свяжем политику с примером тестовой машины. Policy set — набор политик, который платформа запускает вместе. Workspace — отдельное рабочее пространство платформы со своей Terraform-конфигурацией, состоянием и запусками. Мы назначим набор правил рабочему пространству тестового окружения. Terraform-конфигурация и политика могут храниться в разных репозиториях:
terraform-project/
main.tf # aws_instance.web с instance_type
terraform-policies/
sentinel.hcl # подключение правила и уровень блокировки
allowed-instance-types.sentinel # список разрешённых типов и проверка
Ограничение задаётся именно в allowed-instance-types.sentinel:
allowed_types = ["t3.micro", "t3.small"]
А эта часть правила сравнивает instance_type машины из плана с разрешённым списком:
(rc.change.after.instance_type else "") in allowed_types
rc.change.after содержит запланированные значения ресурса после применения. Если в main.tf указано instance_type = "m5.4xlarge", выражение вернёт false: такого значения в списке нет. Следовательно, правило main не пройдёт проверку. Политика ограничивает конкретные типы машин, а не вычисляет количество CPU или объём памяти. Чтобы разрешить другой тип, его нужно явно добавить в список.
Для автоматического запуска проверки в HCP Terraform или Terraform Enterprise:
- Подключите репозиторий
terraform-policiesкак policy set через настройки организации. Если файлы находятся в подкаталоге, укажите его как путь к политикам. - Назначьте policy set workspace тестового окружения, в котором выполняется Terraform-конфигурация из
terraform-project. - Запустите новое выполнение Terraform (run) с формированием плана.
После plan платформа прочитает sentinel.hcl, выполнит allowed-instance-types.sentinel и получит результат правила main. Уровень hard-mandatory остановит переход к apply, если правило вернуло false.
main.tf: instance_type = "m5.4xlarge"
↓ terraform plan
Проверка: "m5.4xlarge" входит в ["t3.micro", "t3.small"]?
↓ false
Политика не пройдена → apply заблокирован
Изменим в main.tf тип машины на t3.micro и запустим новый run:
main.tf: instance_type = "t3.micro"
↓ terraform plan
Проверка: "t3.micro" входит в ["t3.micro", "t3.small"]?
↓ true
Политика пройдена → можно перейти к apply
Успех этой политики не отменяет остальные проверки и ручное согласование, если они настроены. Сама политика не меняет instance_type в коде и не подбирает подходящий размер: разработчик исправляет конфигурацию самостоятельно. При обычном локальном запуске Terraform CLI файлы Sentinel автоматически не выполняются.
Для классических Sentinel policy checks используются уровни:
advisory— сообщает о нарушении, но не блокирует выполнение.soft-mandatory— блокирует выполнение с возможностью override пользователем с нужными правами.hard-mandatory— блокирует выполнение без override.
Механизм policy evaluations может иначе представлять уровни в интерфейсе; при настройке сверяйтесь с документацией используемой платформы.
OPA: проверяем обязательный тег Owner
Теперь рассмотрим вариант без платформы HashiCorp. OPA — отдельная программа: она не создаёт виртуальные машины и не запускает Terraform. Мы передадим ей план и файл правил, а затем посмотрим результат.
План передаётся в формате JSON — текстовом представлении данных с полями и значениями. Правила для OPA пишутся на языке Rego. Учить весь язык для этого примера не требуется: разберём, какие данные читает правило и какое нарушение оно ищет. Попробуем проверить наличие тега Owner: у каждого управляемого aws_instance, который останется после применения, этот тег должен содержать непустое значение. Для примера воспользуемся OPA 1.x.
Перед началом установите Terraform и OPA, настройте доступ к AWS и подготовьте Terraform-конфигурацию. Команды ниже выполняются из каталога этой конфигурации.
Сначала сохраняем план и преобразуем его в JSON:
terraform init
terraform validate
terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
Здесь -out=tfplan сохраняет план в файл, а terraform show -json записывает его представление в tfplan.json. Именно этот JSON прочитает OPA.
Создадим каталог policy и сохраним правило в файл policy/terraform.rego:
package terraform
import rego.v1
deny contains msg if {
some rc in input.resource_changes
rc.mode == "managed"
rc.type == "aws_instance"
rc.change.after != null
tags := object.get(rc.change.after, "tags", {})
owner := object.get(tags, "Owner", "")
not valid_owner(owner)
msg := sprintf("%s: требуется непустой тег Owner", [rc.address])
}
valid_owner(owner) if {
is_string(owner)
trim_space(owner) != ""
}
В данном примере deny собирает сообщения о нарушениях. Функция valid_owner проверяет, что значение тега является строкой и после удаления пробелов по краям не остаётся пустым.
Правило использует tags, то есть требует явно заданный тег ресурса. Если организация допускает теги из default_tags AWS provider, проверять нужно tags_all, учитывая неизвестные значения и поведение закреплённой версии провайдера.
При неизвестном Owner значение отсутствует в after или представлено как null: такой план будет отклонён. Подробную информацию о неизвестных атрибутах Terraform хранит в after_unknown; сложные политики должны обрабатывать её явно.
Выполним проверку и посмотрим результат:
opa eval --format pretty \
--data policy/terraform.rego \
--input tfplan.json \
'data.terraform.deny'
В этой команде --data указывает файл правил, --input — файл проверяемого плана, а data.terraform.deny запрашивает собранные правилом сообщения. --format pretty делает вывод удобнее для чтения.
Если у ресурса aws_instance.web отсутствует тег Owner, получим следующий результат:
[
"aws_instance.web: требуется непустой тег Owner"
]
Как видим, в сообщении указаны адрес ресурса и причина отказа. Добавьте непустой тег Owner и сформируйте план заново: если других нарушений нет, результатом проверки будет пустой список [].
Обычный opa eval может завершиться успешно даже при непустом списке нарушений. Для блокировки CI проверяем булево выражение с --fail:
set -euo pipefail
terraform init -input=false
terraform validate
terraform plan -input=false -out=tfplan
terraform show -json tfplan > tfplan.json
opa eval --fail --format pretty \
--data policy/terraform.rego \
--input tfplan.json \
'count(data.terraform.deny) == 0'
terraform apply -input=false tfplan
Этот Bash-сценарий предполагает установленные Terraform и OPA, настроенный backend и учётные данные провайдера. При нарушении выражение не даёт успешного результата, OPA возвращает ненулевой код, а оболочка останавливается до apply. В реальном pipeline между проверкой и применением можно добавить ручное согласование.
Применяется именно сохранённый tfplan. Повторный terraform plan после проверки создаст другой артефакт, для которого политики потребуется выполнить заново.
Какие сценарии проверить
Для правила Owner нужны как минимум такие входные планы:
| Сценарий | Ожидаемый результат |
|---|---|
| Создание EC2 с Owner=platform | Разрешить |
| Создание EC2 без Owner | Запретить |
| Owner содержит только пробелы | Запретить |
| Owner неизвестен до apply | Запретить |
| Обновление EC2 удаляет Owner | Запретить |
| Чистое удаление EC2 | Разрешить |
| EC2 находится во вложенном модуле | Проверить по тем же правилам |
resource_changes содержит адреса ресурсов из модулей, поэтому дополнительный обход дерева модулей в этих примерах не нужен. Правила проверяют и существующие EC2 без изменений: старый ресурс без тега тоже может заблокировать запуск. Если требуется проверять только создание и обновление, добавьте фильтр по change.actions.
Как внедрять политики
Начните с нескольких понятных правил: разрешённые размеры машин, обязательные теги и запрет удаления выбранных ресурсов. Сначала соберите нарушения в режиме отчётности, исправьте существующие конфигурации и затем включайте блокировку.
- Храните политики в Git и проверяйте изменения через review.
- Закрепляйте версии Terraform, провайдеров и движка политик.
- Добавляйте положительные и отрицательные примеры планов к каждому правилу.
- Защитите CI и репозиторий политик от обхода проверок.
- Оформляйте исключения с владельцем, причиной и сроком действия.
JSON-план может содержать чувствительные значения в открытом виде. Ограничивайте доступ к нему, не публикуйте его в логах и задайте срок хранения артефактов. Проверка плана также не заменяет ограничения доступа в облаке: изменения вне Terraform требуют отдельного контроля.