Skip to content

Проверка политик

TerraCi интегрирует Open Policy Agent (OPA) для применения правил соответствия к Terraform планам. Политики пишутся на Rego v1.

Базовая конфигурация

yaml
extensions:
  policy:
    enabled: true
    sources:
      - type: path
        path: terraform           # имя директории = имя Rego package
    namespaces:
      - terraform
    decisions:
      deny: block
      warn: warn

Параметры конфигурации

enabled

Включение/отключение проверки политик глобально.

yaml
extensions:
  policy:
    enabled: true  # по умолчанию: false

sources

Список источников политик. Каждый источник — директория с .rego файлами. Имя директории должно совпадать с package декларацией внутри файлов.

Локальный путь

yaml
extensions:
  policy:
    sources:
      - type: path
        path: terraform           # package terraform → data.terraform.deny/warn
      - type: path
        path: compliance          # package compliance → data.compliance.deny/warn

Git репозиторий

yaml
extensions:
  policy:
    sources:
      - type: git
        url: https://github.com/org/terraform-policies.git
        ref: main

OCI реестр

yaml
extensions:
  policy:
    sources:
      - type: oci
        url: oci://ghcr.io/org/policies:v1.0

namespaces

Rego пакеты для проверки. TerraCi запрашивает data.<namespace>.deny и data.<namespace>.warn для каждого namespace.

yaml
extensions:
  policy:
    namespaces:
      - terraform              # data.terraform.deny, data.terraform.warn
      - compliance             # data.compliance.deny, data.compliance.warn

По умолчанию: ["terraform"]

Несколько namespace позволяют разделять ответственность — правила безопасности в terraform, контроль расходов в compliance и т.д.

decisions

Действия для OPA решений:

ЗначениеОписание
blockЗавершить пайплайн с ошибкой (код возврата 1) — по умолчанию
warnПереклассифицировать нарушения в предупреждения (код возврата 0)
ignoreМолча игнорировать
yaml
extensions:
  policy:
    decisions:
      deny: block  # по умолчанию
      warn: warn   # по умолчанию

decisions.deny применяется к правилам Rego deny. decisions.warn применяется к правилам Rego warn.

source_cache_dir

Директория для кэширования загруженных политик (git/OCI источники).

yaml
extensions:
  policy:
    source_cache_dir: .terraci/policies  # по умолчанию

overrides

Переопределение настроек для конкретных модулей через ** glob-паттерны:

yaml
extensions:
  policy:
    enabled: true
    decisions:
      deny: block

    overrides:
      # Sandbox: переклассифицировать ошибки в предупреждения
      - match: "**/sandbox/**"
        decisions:
          deny: warn

      # Legacy: полностью отключить проверки
      - match: "legacy/**"
        enabled: false

      # Production: добавить compliance namespace
      - match: "**/prod/**"
        namespaces:
          - terraform
          - compliance

Glob-паттерны

ПаттернСовпадаетНЕ совпадает
**/sandbox/**platform/sandbox/eu-central-1/testplatform/stage/eu-central-1/app
legacy/**legacy/old/eu-central-1/dbplatform/legacy/module
**/prod/**platform/prod/eu-central-1/vpcplatform/stage/eu-central-1/vpc
  • ** — любое количество сегментов пути (включая ноль)
  • * — один сегмент пути

Поведение overrides

  • decisions.deny: warn — deny нарушения переклассифицируются в предупреждения (отображаются, но не блокируют)
  • enabled: false — модуль полностью пропускается, без evaluation
  • namespaces: [...] — заменяет список namespace для совпадающих модулей
  • Несколько overrides могут совпасть — применяются по порядку

Написание политик

Политики используют OPA v1 Rego синтаксис с import rego.v1.

Правила Deny (блокировка деплоя)

rego
package terraform

import rego.v1

# METADATA
# description: Запрет публичных S3 бакетов
# entrypoint: true
deny contains msg if {
    some resource in input.plan.resource_changes
    resource.type == "aws_s3_bucket"
    not "delete" in resource.change.actions
    resource.change.after.acl == "public-read"
    msg := sprintf("S3 bucket '%s' не должен быть публичным", [resource.name])
}

Правила Warn (предупреждение)

rego
warn contains msg if {
    some resource in input.plan.resource_changes
    resource.type == "aws_s3_bucket"
    not "delete" in resource.change.actions
    not has_versioning(resource)
    msg := sprintf("S3 bucket '%s' должен иметь versioning", [resource.name])
}

has_versioning(resource) if {
    some v in resource.change.after.versioning
    v.enabled == true
}

Ключевые паттерны Rego

ПаттернНазначение
some resource in input.plan.resource_changesИтерация ресурсов (не [_])
"create" in resource.change.actionsПроверка членства
not "delete" in resource.change.actionsОтрицание членства
resource.type in taggable_typesПроверка значения в списке
deny contains msg if { ... }Блокирующее правило
warn contains msg if { ... }Предупреждающее правило

Линтинг

Проверяйте политики с помощью Regal: regal lint terraform/ compliance/

Несколько namespace

Разделяйте политики по ответственности — каждая директория = Rego package:

terraform/          → package terraform    (безопасность)
  tags.rego
  s3.rego
compliance/         → package compliance   (контроль расходов)
  cost.rego
yaml
extensions:
  policy:
    sources:
      - type: path
        path: terraform
      - type: path
        path: compliance
    namespaces:
      - terraform
      - compliance

Структура Input

Политики получают envelope с контекстом TerraCi и raw Terraform plan JSON в input.plan:

json
{
  "terraci": {
    "module": {
      "path": "platform/prod/eu-central-1/vpc",
      "components": {
        "service": "platform",
        "environment": "prod",
        "region": "eu-central-1",
        "module": "vpc"
      }
    },
    "policy": { "namespaces": ["terraform"] },
    "plan": { "path": "platform/prod/eu-central-1/vpc/plan.json" }
  },
  "plan": {
    "format_version": "1.2",
    "resource_changes": [
      {
        "type": "aws_s3_bucket",
        "name": "example",
        "change": {
          "actions": ["create"],
          "before": null,
          "after": {
            "bucket": "my-bucket",
            "acl": "private",
            "tags": { "Environment": "stage" }
          }
        }
      }
    ]
  }
}

Генерируемый пайплайн

При включении политик TerraCi добавляет стадию policy-check между plan и apply:

GitLab CI:

yaml
stages:
  - deploy-0
  - policy-check
  - deploy-1

policy-check:
  stage: policy-check
  script:
    - terraci policy check --format text
  needs: [plan-vpc, plan-eks]

GitHub Actions:

yaml
jobs:
  policy-check:
    needs: [plan-vpc, plan-eks]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/download-artifact@v4
      - run: terraci policy check --format text

Команды

bash
terraci policy pull                                    # Материализовать политики вручную
terraci policy check                                   # Проверить все модули
terraci policy check --module platform/prod/.../vpc    # Один модуль
terraci policy check --format json                     # JSON вывод
terraci policy check -v                                # Подробный вывод

Интеграция с MR/PR

Результаты включаются в комментарий MR/PR:

markdown
### ❌ Проверка политик

**5** модулей: ✅ **2** ок | ⚠️ **1** предупреждения | ❌ **2** ошибки

<details>
<summary>❌ Ошибки (2)</summary>

**platform/stage/eu-central-1/bad:**
- `terraform`: S3 bucket 'public' не должен быть публичным
- `compliance`: Instance 'web' использует дорогой тип 'p4d.24xlarge'

</details>

Примеры

См. examples/policy-checks — рабочий пример с:

  • Двумя namespace (terraform + compliance)
  • Пятью модулями (pass, warn, fail, skip)
  • Overrides для sandbox и legacy
  • Rego-политиками, проходящими Regal lint

Смотрите также

Released under the MIT License.