Статья Безопасность Infrastructure as Code: от мисконфигурации в Terraform до detection-правила в SIEM

Силуэт оператора со спины в тёмной комнате перед монитором с зелёным свечением. Экран отображает вывод сканера IaC с ошибкой мисконфигурации S3-бакета.


Утечка Capital One - избыточные привилегии IAM-роли на EC2-инстансе. Майнинг криптовалюты на сайте Los Angeles Times - S3-бакет с ACL public-read-write. Внедрение вредоносного кода в Twilio TaskRouter JS SDK (2020) - ещё один S3-бакет, открытый на запись для анонимных пользователей. Три громких инцидента, три мисконфигурации, которые ловятся одним проходом checkov -d . по Terraform-шаблону. NSA в отчёте Mitigating Cloud Vulnerabilities (январь 2020) называет мисконфигурации наиболее распространённой уязвимостью облачных сред. А по данным IBM Cost of a Data Breach Report, средняя стоимость инцидента из-за cloud misconfiguration измеряется миллионами долларов - при этом среднее время обнаружения и containment часто превышает шесть месяцев. Я настраиваю IaC-сканирование в CI/CD-пайплайнах на production-стеках AWS и GCP четвёртый год. За это время ни одна найденная инструментом проблема не добралась до прода. Но я точно знаю, какие мисконфигурации инструменты стабильно пропускают.

Пять категорий мисконфигураций облачной инфраструктуры и их маппинг на MITRE ATT&CK

Тысячи встроенных правил в IaC-сканерах укладываются в пять устойчивых категорий. Для blue team каждая категория - конкретный enabler для тактик атакующих, и понимание маппинга позволяет строить detection-правила параллельно с preventive-сканированием.

Публичный доступ к ресурсам. S3-бакет с ACL public-read, RDS-инстанс с publicly_accessible = true, Azure Storage Account с включённым публичным доступом к blob, Kubernetes Service типа LoadBalancer без ограничения source IP. Атакующий использует Cloud Infrastructure Discovery (T1580, Discovery) для обнаружения открытых ресурсов - автоматизированные сканеры вроде Grayhat Warfare находят публичные бакеты за минуты. Detection в SIEM: алерт на CloudTrail-события PutBucketAcl и ModifyDBInstance с публичными параметрами, источник - не CI/CD service role.

Избыточные IAM-привилегии. Политика с "Action": "[I]" и "Resource": "[/I]", сервисный аккаунт GCP с roles/owner на весь проект, Kubernetes ClusterRoleBinding с cluster-admin для рабочей нагрузки. Прямой enabler для Cloud Accounts (T1078.004, Initial Access / Privilege Escalation) - скомпрометированная роль с wildcard-доступом даёт полный контроль над аккаунтом. Detection: алерты на CreatePolicy и AttachRolePolicy с wildcard в полях Action или Resource.

Отсутствие шифрования. EBS-тома без encrypted = true, RDS без storage_encrypted, S3 без server-side encryption, HTTP-listener на ALB без TLS-терминации. Открывает путь к Credentials In Files (T1552.001, Credential Access) и Private Keys (T1552.004, Credential Access) - атакующий получает данные в открытом виде при перехвате трафика или доступе к хранилищу. Detection: CreateVolume без KmsKeyId, CreateDBInstance без StorageEncrypted.

Отсутствие логирования. CloudTrail отключён в части регионов, VPC Flow Logs не настроены, S3 server access logging пропущено, Kubernetes audit logging выключен на API-сервере. Атакующий эксплуатирует Disable or Modify Cloud Logs (T1562.008, Defense Evasion) - и уже существующий пробел в логировании делает evasion тривиальным. Detection: периодический аудит через DescribeTrails, DescribeFlowLogs, AWS Config Rules на полноту логирования.

Избыточный сетевой доступ. Security Group с 0.0.0.0/0 на порт 22 или 3389, отсутствие NetworkPolicy в Kubernetes (все поды общаются со всеми), NACL без explicit deny. Расширяет attack surface для начального доступа и lateral movement. Detection: алерты на AuthorizeSecurityGroupIngress с CIDR 0.0.0.0/0 для критичных портов.

Каждая из пяти категорий в pipeline ловится за секунды - в проде обнаруживается за недели. Вот конкретный пример мисконфигурации, с которой начинается Capital One-подобный инцидент:
Код:
resource "aws_s3_bucket" "data" {
  bucket = "customer-reports"
  acl    = "public-read-write"
}

resource "aws_iam_role_policy" "ec2_role" {
  role   = aws_iam_role.app.id
  policy = jsonencode({
    Statement = [{ Action = "*", Resource = "*", Effect = "Allow" }]
  })
}
Два ресурса, два CRITICAL finding - Checkov поймает оба за долю секунды. Но только если сканирование вообще настроено.

SAST для Terraform и CloudFormation: HCL-код vs Terraform Plan

Инструменты статического анализа IaC делятся на два подхода, и выбор между ними напрямую влияет на точность detection.

Сканирование HCL/YAML-кода напрямую работает без подключения к cloud API, не требует credentials, отрабатывает за секунды. Ставится как pre-commit hook или первый шаг CI. Поддерживает Terraform HCL, CloudFormation YAML/JSON, Kubernetes-манифесты, Helm-чарты, ARM-шаблоны. Минус: не видит результат интерполяции переменных, dynamic-блоков и data sources. Если значение ACL приходит из var.bucket_acl, а дефолт - private, сканер понятия не имеет, что при деплое переменную переопределят на public-read-write через -var флаг.

Сканирование Terraform Plan (JSON) запускается после terraform plan -out=plan.tfplan && terraform show -json plan.tfplan > plan.json, когда все переменные уже разрешены. Видит реальные значения, которые будут применены. Минус: требует доступ к state backend и cloud API, медленнее, нужна аутентификация. Как отмечает Christophe Tafani-Dereeper в исследовании Terraform static analysis workflow: «lots of Terraform code use extensively input variables, dynamic data sources and complex HCL expressions that can easily become security issues you can't easily catch just by looking at the source code».

С Pulumi ситуация хитрее. Pulumi использует полноценные языки программирования (TypeScript, Python, Go), и статический анализ HCL-подобного синтаксиса к нему неприменим. Checkov и KICS поддерживают Pulumi-ресурсы, но анализируют скомпилированный state, а не исходный код - по природе это ближе к план-сканированию. Если ваш стек на Pulumi, учитывайте при выборе инструмента.

Рекомендация для CI/CD: HCL-скан на этапе PR (быстрый feedback, advisory), план-скан перед terraform apply (точный результат, blocking gate). Два gate - две линии обороны.

Checkov, Trivy, Terrascan, KICS - сравнение IaC security tools​

Четыре инструмента, которые реально работают в production CI/CD. Без маркетинговой шелухи:

КритерийCheckovTrivyTerrascanKICS
IaC-форматыTerraform, CFn, Pulumi, K8s, ARM, HelmTerraform, CFn, K8s, Helm, DockerTerraform, CFn, K8s, Helm, ARMTerraform, CFn, K8s, Helm, Docker, Ansible, Pulumi
Тип сканированияHCL + PlanHCL + PlanHCL + Plan (Rego)HCL + Plan (Rego)
Кастомные политикиPython, YAMLRegoRegoRego
Встроенных правил1000+800+500+1500+
CI/CD интеграцияGitHub Actions, GitLab CI, JenkinsGitHub Actions, GitLab CIGitHub Actions, GitLab CIGitHub Actions, GitLab CI
ВендорPalo Alto (Prisma Cloud)Aqua SecurityTenableCheckmarx

Статус поддержки и выбор под стек​

Checkov (bridgecrewio/checkov) - активно поддерживается, еженедельные релизы, де-факто стандарт для входа в IaC security. Кастомные проверки на Python - порог входа низкий, Rego учить не надо.

Trivy (aquasecurity/trivy) - активно поддерживается. Важный момент: tfsec (ранее самостоятельный проект) переведён в maintenance mode в 2023, активная разработка перенесена в Trivy через общий движок. Если вы ещё используете tfsec отдельно - миграция на Trivy закроет и IaC-сканирование, и контейнеры, и SCA одним инструментом.

Terrascan (tenable/terrascan) - приобретён Tenable в 2021, но активность разработки заметно просела с 2023 года (перед использованием проверьте дату последнего релиза - можете удивиться). Сильная сторона - Rego-политики, переиспользуемые с OPA Gatekeeper в Kubernetes. Если у команды есть OPA-экспертиза, Terrascan ложится в стек органично.

KICS (Checkmarx/kics) - наибольшее количество встроенных правил (1500+), самый широкий охват IaC-форматов. Активный open-source проект с community-контрибуциями.

Как выбирать: если уже есть Trivy для контейнеров - добавьте IaC-сканирование туда, не плодите зоопарк. Нужен самый широкий охват из коробки - KICS. Нужна Python-кастомизация без изучения Rego - Checkov. Всё на OPA - Terrascan.

Shift-left на практике: поиск уязвимостей в Terraform через CI/CD​

Требования к окружению​

  • ОС: Linux (Ubuntu 20.04+), macOS, Windows (WSL2)
  • Python: 3.8+ (для Checkov) или бинарный релиз Trivy/KICS
  • RAM: от 512 МБ для сканирования малых проектов, 2+ ГБ для проектов с 100+ ресурсами
  • Terraform: 1.0+ для план-сканирования (опционально для HCL-скана)
  • CI/CD: GitHub Actions или GitLab CI (примеры ниже)
  • Сеть: доступ к PyPI или GitHub Releases для установки; далее работает offline

Настройка и первый скан​

Установка Checkov: pip install checkov. Запуск: checkov -d . --framework terraform. Для Trivy: скачайте бинарник, запустите trivy config .. Первый скан по типичному Terraform-проекту выдаст от 30 до 200 findings. Не паникуйте - блокируйте в CI только CRITICAL и HIGH, MEDIUM оставьте как warning в PR-комментариях.

Пример конфигурации GitHub Actions:
YAML:
- name: Checkov IaC scan
  uses: bridgecrewio/checkov-action@master
  with:
    directory: ./terraform
    framework: terraform
    check: CKV_AWS_18,CKV_AWS_19,CKV_AWS_145
    soft_fail: false
Параметр check ограничивает скан тремя конкретными проверками (CKV_AWS_18 - access logging, CKV_AWS_19 - SSE enabled, CKV_AWS_145 - encryption with customer-managed KMS key). Начинайте с 10–15 высокоприоритетных правил и расширяйте по мере устранения findings. Иначе разработчики начнут массово лепить #checkov:skip аннотации, и сканер превратится в декорацию.

Кастомная политика: когда дефолтных правил недостаточно​

Когда compliance требует проверку, которой нет в стандартном наборе - пишите свою. Пример кастомной проверки Checkov для безопасности CloudFormation и Terraform (адаптировано из исследования Christophe Tafani-Dereeper):
Python:
from checkov.common.models.enums import CheckResult, CheckCategories
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck

class S3Encrypted(BaseResourceCheck):
    def __init__(self):
        super().__init__("S3 encrypted at rest", "CUSTOM_001",
            [CheckCategories.ENCRYPTION], ["aws_s3_bucket"])
    def scan_resource_conf(self, conf):
        if "server_side_encryption_configuration" not in conf:
            return CheckResult.FAILED
        return CheckResult.PASSED
scanner = S3Encrypted()
# Примечание: для AWS provider 4.x+ SSE настраивается отдельным ресурсом
# aws_s3_bucket_server_side_encryption_configuration - проверка должна
# сканировать этот ресурс, а не блок внутри aws_s3_bucket.
Запуск: checkov -d . --external-checks-dir ./custom_checks -c CUSTOM_001. Для Terrascan и KICS аналогичная проверка пишется на Rego, для Trivy (включая унаследованный синтаксис tfsec) - в YAML-формате.

Четыре уровня gate в зрелом пайплайне

По данным GraphNode Software, зрелая интеграция строится в четыре уровня:
  1. Pre-commit hook - лёгкий скан изменённых файлов, advisory mode. Мгновенная обратная связь до push.
  2. PR check - полный скан diff, результаты в PR-комментарии. Findings выше порога severity блокируют merge.
  3. Pipeline gate - скан после terraform plan, на основе plan.json. Ловит мисконфигурации, невидимые при HCL-сканировании.
  4. Admission controller - для Kubernetes: OPA Gatekeeper или Kyverno. Последний рубеж: даже если мисконфигурация прошла все предыдущие gate, admission controller отклоняет kubectl apply. Соответствует требованиям Kubernetes STIG (DISA).

Слепые зоны статического анализа IaC: что пропускают все сканеры​

Ни Checkov, ни Trivy, ни KICS не покрывают следующие векторы. Для detection-инженера это must-know.
🔓 Часть контента скрыта: Эксклюзивный контент для зарегистрированных пользователей.


Вот что из этого следует на практике: IaC-сканер - это первая линия, не единственная. Без CSPM и SIEM-правил на drift вы закрываете только половину картины.

Detection-чеклист для SOC: корреляция IaC-событий с облачными алертами​

Для SOC-команды - маппинг мисконфигураций облачной инфраструктуры на CloudTrail-события:

IaC-мисконфигурацияCloudTrail EventSeverityMITRE ATT&CK
S3 ACL public-read/writePutBucketAcl, PutBucketPolicyCRITICALT1580
IAM policy Action: *CreatePolicy, PutRolePolicyHIGHT1078.004
SG 0.0.0.0/0 на SSH/RDPAuthorizeSecurityGroupIngressHIGHT1580
RDS publicly_accessibleModifyDBInstanceHIGHT1580
CloudTrail disabledStopLogging, DeleteTrailCRITICALT1562.008
EBS volume unencryptedCreateVolume (без KmsKeyId)MEDIUMT1552.001
State file accesseds3:GetObject (*.tfstate)HIGHT1552.001
IaC repo modifiedMEDIUMT1213.003
TD [/TD]

Базовое корреляционное правило: если PutBucketAcl с параметром, содержащим public, произошёл НЕ от CI/CD service role - это ручное изменение, priority 1 alert. Второй уровень: если тот же бакет описан в IaC-репозитории с acl = "private" - автоматический тикет на configuration drift.

Shift-left через IaC-сканирование не заменяет runtime detection. Это два дополняющих слоя: SAST для IaC ловит мисконфигурацию до деплоя, CSPM и SIEM - drift и ручные изменения после. Вместе они закрывают полный цикл от кода до алерта.

Из четырёх лет работы с DevSecOps Infrastructure as Code в CI/CD я вынес одно наблюдение, которое редко обсуждают: проблема - не инструменты. Checkov, Trivy, KICS - все ловят 80% типовых мисконфигураций из коробки. Проблема - в suppression annotations. Разработчик получает 47 findings на PR, блокирующих merge. Что он делает? Лепит #checkov:skip=CKV_AWS_18 к каждому ресурсу. Через три месяца в репозитории 200+ skip-комментариев, и сканер - формальность. Я видел это в нескольких компаниях, где аудировал IaC-пайплайны. Решение: ограничьте initial ruleset десятью–пятнадцатью проверками с реальным blast radius - public S3, wildcard IAM, disabled CloudTrail, unencrypted RDS/EBS, open SSH - доведите suppression rate до нуля, потом расширяйте. И обязательно - отдельный pipeline job, который периодически считает density skip-аннотаций в репозитории и поднимает алерт при росте. Без этого механизма shift-left превращается в shift-checkbox, и первый же инцидент с публичным бакетом будет найден не сканером, а исследователем снаружи. Если строите подобный пайплайн и упираетесь в сопротивление разработчиков - на codeby.net обсуждаем рабочие suppression-стратегии и ruleset-конфигурации для разных облачных стеков.
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab