Modern QA2026Политики как код
Join

Course08 Infrastructure as Code Testing

Cutting-edge · Chapter 08

Политики как код

Updated Jul 2026

Почему политики должны быть кодом

Инструменты статического анализа выявляют то, что terraform validate не может: ошибки конфигурации безопасности, нарушения комплаенса и несоответствия организационным политикам. Ключевой вывод: политики, записанные в документации, игнорируются, тогда как политики, записанные в коде, применяются автоматически при каждом коммите.

Политики как код превращают утверждения вроде «все S3-бакеты должны быть зашифрованы» из вики-страницы, которую разработчики забывают читать, в автоматический рубеж, блокирующий несоответствующую инфраструктуру от попадания в продакшен.

Сравнение инструментов

Инструмент Язык Область применения Скорость Пользовательские правила Интеграция с CI
tfsec Go Только Terraform Очень быстро Rego, YAML Нативный GitHub Action
Checkov Python Terraform, CloudFormation, K8s, Helm, Dockerfiles Быстро Python Все основные CI-системы
Trivy (режим config) Go Terraform, CloudFormation, K8s, Dockerfiles Очень быстро Rego GitHub Action, шаблон GitLab
OPA/Conftest Rego Любые структурированные данные (JSON, YAML, HCL) Быстро Rego (нативно) Любой CI через CLI
Bridgecrew SaaS + Python Множество фреймворков Быстро Python (расширяет Checkov) Полная платформа + CLI
Snyk IaC SaaS + CLI Terraform, CloudFormation, K8s, ARM Умеренно Через UI Все основные CI-системы

Выбор между этими инструментами зависит от вашего стека, навыков команды и требований комплаенса. Многие команды используют несколько инструментов в комбинации — например, Checkov для широкого покрытия плюс OPA для пользовательских организационных политик.

OPA/Rego: универсальный движок политик

Open Policy Agent (OPA) оценивает структурированные данные по политикам Rego. Это наиболее гибкий подход, потому что он работает с любым форматом инфраструктуры — планами Terraform, манифестами Kubernetes, файлами Docker Compose или любой конфигурацией в JSON/YAML.

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

# policy/terraform/s3.rego
package terraform.s3

# Deny S3 buckets without encryption
deny[msg] {
    resource := input.resource_changes[_]
    resource.type == "aws_s3_bucket"
    not has_encryption(resource)
    msg := sprintf("S3 bucket '%s' must have server-side encryption enabled", [resource.address])
}

has_encryption(resource) {
    resource.change.after.server_side_encryption_configuration[_].rule[_].apply_server_side_encryption_by_default[_].sse_algorithm
}

# Deny public ACLs
deny[msg] {
    resource := input.resource_changes[_]
    resource.type == "aws_s3_bucket"
    acl := resource.change.after.acl
    acl != "private"
    msg := sprintf("S3 bucket '%s' has ACL '%s' -- must be 'private'", [resource.address, acl])
}

# Deny buckets without versioning
deny[msg] {
    resource := input.resource_changes[_]
    resource.type == "aws_s3_bucket"
    not has_versioning(resource)
    msg := sprintf("S3 bucket '%s' must have versioning enabled", [resource.address])
}

has_versioning(resource) {
    resource.change.after.versioning[_].enabled == true
}

Запуск OPA с Conftest

Conftest — это CLI-инструмент, который запускает политики OPA на конфигурационных файлах:

# Run policy against a Terraform plan
terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
conftest test tfplan.json --policy policy/terraform/

# Run against Kubernetes manifests
conftest test k8s/deployment.yaml --policy policy/kubernetes/

# Run against Dockerfiles
conftest test Dockerfile --policy policy/docker/

# Run with multiple policy directories
conftest test tfplan.json \
  --policy policy/security/ \
  --policy policy/compliance/ \
  --policy policy/cost/

Организация политик Rego по категориям

Хорошо организованный репозиторий политик разделяет ответственности:

policy/
  terraform/
    s3.rego          # Правила для S3
    rds.rego         # Правила для RDS
    iam.rego         # Правила IAM-политик
    networking.rego  # Правила VPC, групп безопасности
    tagging.rego     # Требования к тегированию ресурсов
  kubernetes/
    security.rego    # Безопасность подов, RBAC
    resources.rego   # Лимиты CPU/памяти
    networking.rego  # Сетевые политики
  docker/
    best_practices.rego  # Линтинг Dockerfile
  common/
    helpers.rego     # Общие вспомогательные функции

Продвинутые паттерны Rego

# policy/terraform/iam.rego
package terraform.iam

# Deny IAM policies with wildcard actions
deny[msg] {
    resource := input.resource_changes[_]
    resource.type == "aws_iam_policy"
    policy_doc := json.unmarshal(resource.change.after.policy)
    statement := policy_doc.Statement[_]
    statement.Effect == "Allow"
    statement.Action[_] == "*"
    msg := sprintf("IAM policy '%s' grants wildcard actions (*). Use specific actions.",
        [resource.address])
}

# Deny IAM policies with wildcard resources on mutating actions
deny[msg] {
    resource := input.resource_changes[_]
    resource.type == "aws_iam_policy"
    policy_doc := json.unmarshal(resource.change.after.policy)
    statement := policy_doc.Statement[_]
    statement.Effect == "Allow"
    statement.Resource[_] == "*"
    action := statement.Action[_]
    not is_readonly_action(action)
    msg := sprintf("IAM policy '%s' uses wildcard resource with mutating action '%s'",
        [resource.address, action])
}

is_readonly_action(action) {
    endswith(action, ":Get*")
}
is_readonly_action(action) {
    endswith(action, ":List*")
}
is_readonly_action(action) {
    endswith(action, ":Describe*")
}

Checkov: всё включено

Checkov поставляется с более чем 1000 встроенных правил и не требует конфигурации для начала обнаружения проблем. Он особенно хорош для команд, которым нужна немедленная отдача без написания собственных политик.

Быстрый старт

# Scan a Terraform directory
checkov -d ./terraform/ --framework terraform

# Output example:
# Passed checks: 42, Failed checks: 3, Skipped: 0
#
# Check: CKV_AWS_18: "Ensure the S3 bucket has access logging enabled"
#   FAILED for resource: aws_s3_bucket.data
#   File: /main.tf:15-22
#
# Check: CKV_AWS_145: "Ensure S3 bucket is encrypted with KMS"
#   FAILED for resource: aws_s3_bucket.data
#   File: /main.tf:15-22

# Run only specific checks
checkov -d ./terraform/ --check CKV_AWS_18,CKV_AWS_145

# Skip specific checks (with justification)
checkov -d ./terraform/ --skip-check CKV_AWS_18 \
  --skip-check-reason "Access logging handled by CloudTrail"

# Output as JSON for CI parsing
checkov -d ./terraform/ --output json > checkov-results.json

# Scan multiple frameworks at once
checkov -d . --framework terraform,kubernetes,dockerfile

Пользовательские политики Checkov на Python

Когда встроенных проверок недостаточно, пишите собственные политики на Python:

# custom_checks/s3_naming_convention.py
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories

class S3NamingConvention(BaseResourceCheck):
    """Ensure S3 bucket names follow organizational naming convention."""

    def __init__(self):
        name = "Ensure S3 bucket follows naming convention: {team}-{env}-{purpose}"
        id = "CUSTOM_S3_001"
        supported_resources = ["aws_s3_bucket"]
        categories = [CheckCategories.CONVENTION]
        super().__init__(name=name, id=id, categories=categories,
                        supported_resources=supported_resources)

    def scan_resource_conf(self, conf):
        bucket_name = conf.get("bucket", [""])[0]
        # Pattern: team-environment-purpose
        parts = bucket_name.split("-")
        if len(parts) < 3:
            return CheckResult.FAILED
        valid_envs = ["dev", "staging", "prod", "test"]
        if parts[1] not in valid_envs:
            return CheckResult.FAILED
        return CheckResult.PASSED

check = S3NamingConvention()

Интеграция с pre-commit

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/bridgecrewio/checkov
    rev: '3.2.0'
    hooks:
      - id: checkov
        args: ['--compact', '--framework', 'terraform']

Комбинирование инструментов в CI-пайплайне

Наиболее надёжный подход использует несколько инструментов, каждый из которых выявляет разные классы проблем:

# .github/workflows/iac-policy.yml
name: IaC Policy Checks
on:
  pull_request:
    paths:
      - 'terraform/**'
      - 'k8s/**'

jobs:
  policy-checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: tfsec (fast, Terraform-specific)
        uses: aquasecurity/tfsec-action@v1.0.0
        with:
          working_directory: ./terraform/
          soft_fail: false

      - name: Checkov (broad coverage, multi-framework)
        uses: bridgecrewio/checkov-action@master
        with:
          directory: .
          framework: terraform,kubernetes,dockerfile
          output_format: cli,json
          output_file_path: console,checkov-results.json

      - name: OPA/Conftest (custom organizational policies)
        run: |
          terraform -chdir=terraform plan -out=tfplan
          terraform -chdir=terraform show -json tfplan > tfplan.json
          conftest test tfplan.json --policy policy/ --output json > opa-results.json

      - name: Trivy config scan (Dockerfiles + K8s)
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'config'
          scan-ref: '.'
          severity: 'HIGH,CRITICAL'

Выбор комбинации

Профиль команды Рекомендуемый стек Обоснование
Небольшой стартап, только Terraform tfsec + Checkov Быстрая настройка, широкое покрытие, пользовательские политики не нужны
Корпорация, мультиоблако Checkov + OPA/Conftest Checkov для широких проверок, OPA для пользовательского комплаенса
Фокус на безопасности tfsec + OPA + Snyk IaC Глубокая защита, несколько движков сканирования
Kubernetes-ориентированные Checkov + Polaris + OPA Специализированные проверки K8s + пользовательские политики

Ключевой принцип: статические проверки политик должны выполняться менее чем за 60 секунд и блокировать слияние при критических нарушениях. Это ваш наиболее экономически эффективный рубеж контроля качества.