ADG Оставить заявку
Блог DevOps 6 мин чтения

Sentinel policies в Terraform Cloud: policy-as-code для compliance в плане

HashiCorp расширяет Sentinel в Terraform Cloud: policy-as-code прямо в pipeline. Внедряем для клиента с требованиями compliance - запрет открытых SG и обязательные теги.

Контекст момента

HashiCorp представляет расширенные политики Sentinel в Terraform Cloud - policy-as-code для governance инфраструктуры на уровне плана

HashiCorp расширила возможности Sentinel в Terraform Cloud: теперь политики policy-as-code проверяются прямо на этапе плана, до apply, и могут жёстко блокировать изменения или запрашивать ручное подтверждение. Мы как раз находились в середине внедрения Terraform Cloud для клиента с обязательными требованиями по compliance - так что попали в самый нужный момент.

Откуда задача

Клиент - компания из финансового сектора, AWS, несколько команд разработки с разным уровнем опыта работы с инфраструктурой. Требования compliance формулируются через внутреннюю политику безопасности и частично через внешние стандарты. На практике это означало два жёстких правила, которые раньше проверялись только на code review - человеком, вручную, нерегулярно.

Первое - запрет security groups с ingress 0.0.0.0/0. Это классика: кто-то открывает порт «на время дебага» и забывает закрыть. В AWS это означает публично доступный сервис или хуже.

Второе - обязательные теги на ресурсах. У клиента биллинг и аудит завязан на теги Environment, Owner, CostCenter. Ресурс без тега - это дыра в учёте и в разграничении ответственности.

До Sentinel это всё проверялось кодом-ревьюером и иногда AWS Config rules постфактум. Постфактум - это плохо: ресурс уже создан, нарушение уже есть, надо исправлять.

Как работает Sentinel в Terraform Cloud

Sentinel - это язык политик от HashiCorp, интегрированный в несколько их продуктов. В контексте Terraform Cloud он работает так: после terraform plan, но до terraform apply, Sentinel проверяет план на соответствие заданным политикам. Если политика нарушена - apply либо блокируется жёстко (hard-mandatory), либо требует подтверждения от человека с нужными правами (soft-mandatory).

Это принципиально отличается от AWS Config: Sentinel работает на уровне плана, то есть проблема ловится до того, как что-то попало в реальную инфраструктуру. Config смотрит на то, что уже существует.

Сам язык Sentinel напоминает Python с уклоном в декларативность: определяешь правило как функцию, которая возвращает bool, и набор таких правил образует политику.

Политика 1: запрет открытых security groups

Базовый вид политики для ingress 0.0.0.0/0:

import "tfplan/v2" as tfplan

# Найти все security group rules в плане
sg_rules = filter tfplan.resource_changes as _, rc {
    rc.type is "aws_security_group_rule" and
    rc.mode is "managed" and
    rc.change.actions contains "create" or rc.change.actions contains "update"
}

# Проверить что ни одно правило не открыто на весь мир
no_open_ingress = rule {
    all sg_rules as _, rule {
        rule.change.after.type is "egress" or
        (not "0.0.0.0/0" in rule.change.after.cidr_blocks and
         not "::/0" in rule.change.after.ipv6_cidr_blocks)
    }
}

main = rule {
    no_open_ingress
}

На практике пришлось добавить обработку aws_security_group с inline rules - там структура другая, cidr_blocks вложены в ingress блок, а не на верхнем уровне. Это типичная ловушка: AWS провайдер позволяет описывать security groups двумя способами, и политика должна покрывать оба.

Режим: hard-mandatory. Нарушение - план не пройдёт ни при каких условиях, нет никакого «подтвердить вручную».

Политика 2: обязательные теги

Теги проверяются на всех ресурсах, у которых есть атрибут tags. В плане это доступно как change.after.tags:

import "tfplan/v2" as tfplan

required_tags = ["Environment", "Owner", "CostCenter"]

# Ресурсы у которых есть атрибут tags
taggable_resources = filter tfplan.resource_changes as _, rc {
    rc.mode is "managed" and
    (rc.change.actions contains "create" or rc.change.actions contains "update") and
    rc.change.after.tags is not null
}

all_have_required_tags = rule {
    all taggable_resources as _, rc {
        all required_tags as tag {
            tag in keys(rc.change.after.tags) and
            length(rc.change.after.tags[tag]) > 0
        }
    }
}

main = rule {
    all_have_required_tags
}

Тут режим soft-mandatory: если тег отсутствует - план не блокируется автоматически, но apply требует подтверждения от designated reviewer из команды infra. Логика в том, что иногда бывает ресурс, который объективно не принадлежит ни одному Owner - например, общий VPC. Хотели оставить пространство для исключений, но фиксируемых явно, не просто «забыли».

Что обнаружилось в процессе

Когда политики встали в пайплайн, первый прогон дал неожиданно много нарушений по тегам. Не потому что разработчики игнорировали требование - просто несколько terraform-модулей создавали вспомогательные ресурсы (security groups для VPC endpoints, IAM roles) без тегов, потому что авторы модулей не пробрасывали тег-переменную. Это не видно на code review нетренированным глазом.

Пришлось пройтись по модулям и добавить tags = var.tags там, где его не было. Работа неинтересная, но полезная: заодно выяснилось, что пара модулей создавала ресурсы с захардкоженными именами без тегов вообще - наследие 2019 года.

По security groups неожиданных нарушений не было - open ingress никто не писал осознанно. Один раз сработало на копипасте с Stack Overflow: человек скопировал пример с 0.0.0.0/0, не заметил, что это идёт в plan. Sentinel поймал, объяснение в логе понятное, исправление заняло минуту.

Структура в Terraform Cloud

Политики объединяются в policy sets и привязываются к workspace-ам. У клиента три workspace - dev, staging, prod. На dev политики стоят в soft-mandatory режиме для обоих правил (дать разработчикам возможность экспериментировать без блокировки). На staging и prod - hard-mandatory для SG, soft-mandatory для тегов с ревьюером из infra-команды.

Это не идеальная схема: soft-mandatory на dev фактически не влияет на поведение, потому что никто не назначен ревьюером и подтверждение даётся автоматически. Клиент сознательно согласился на такой вариант - dev должен оставаться быстрым, нарушения там некритичны.

Где сейчас

Политики работают в прод около трёх недель. За это время было два подтверждения soft-mandatory на staging - оба по тегам, оба легитимных (общие сетевые ресурсы), оба задокументированы в комментарии к apply. Ни одного hard-mandatory нарушения в staging или prod после первоначальной чистки модулей.

Главное наблюдение: policy-as-code работает не потому что люди «не знают правила», а потому что убирает необходимость помнить о них при каждом изменении. Разработчик думает о своей задаче, а не об аудитных требованиях - и это нормально. Автоматическая проверка в плане закрывает этот пробел без трения в процессе.

Sentinel как язык - непривычный, документация местами скудная, отладка политик происходит в основном методом «запустить и посмотреть на ошибку». Но для несложных governance-правил он справляется, и интеграция с Terraform Cloud плотная - лучше, чем тащить внешний OPA и настраивать хуки самому.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.