Утечка 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" }]
})
}
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. Без маркетинговой шелухи:| Критерий | Checkov | Trivy | Terrascan | KICS |
|---|---|---|---|---|
| IaC-форматы | Terraform, CFn, Pulumi, K8s, ARM, Helm | Terraform, CFn, K8s, Helm, Docker | Terraform, CFn, K8s, Helm, ARM | Terraform, CFn, K8s, Helm, Docker, Ansible, Pulumi |
| Тип сканирования | HCL + Plan | HCL + Plan | HCL + Plan (Rego) | HCL + Plan (Rego) |
| Кастомные политики | Python, YAML | Rego | Rego | Rego |
| Встроенных правил | 1000+ | 800+ | 500+ | 1500+ |
| CI/CD интеграция | GitHub Actions, GitLab CI, Jenkins | GitHub Actions, GitLab CI | GitHub Actions, GitLab CI | GitHub Actions, GitLab CI |
| Вендор | Palo Alto (Prisma Cloud) | Aqua Security | Tenable | Checkmarx |
Статус поддержки и выбор под стек
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, зрелая интеграция строится в четыре уровня:- Pre-commit hook - лёгкий скан изменённых файлов, advisory mode. Мгновенная обратная связь до push.
- PR check - полный скан diff, результаты в PR-комментарии. Findings выше порога severity блокируют merge.
- Pipeline gate - скан после
terraform plan, на основе plan.json. Ловит мисконфигурации, невидимые при HCL-сканировании. - Admission controller - для Kubernetes: OPA Gatekeeper или Kyverno. Последний рубеж: даже если мисконфигурация прошла все предыдущие gate, admission controller отклоняет
kubectl apply. Соответствует требованиям Kubernetes STIG (DISA).
Слепые зоны статического анализа IaC: что пропускают все сканеры
Ни Checkov, ни Trivy, ни KICS не покрывают следующие векторы. Для detection-инженера это must-know.
🔓 Часть контента скрыта: Эксклюзивный контент для зарегистрированных пользователей.
Configuration drift. IaC-сканер проверяет код. Ручное изменение через AWS Console после деплоя - невидимо. Знакомая история: разработчик добавил
0.0.0.0/0 в Security Group через консоль, «чтобы быстро проверить». Terraform state не обновился, сканер молчит, дыра торчит наружу. Митигация: CSPM-инструменты (AWS Config Rules, Azure Policy) как дополнительный слой. Detection в SIEM: алерт на AuthorizeSecurityGroupIngress, когда userIdentity.sessionContext не содержит CI/CD service role ARN.Secrets в Terraform state. State-файл содержит plaintext-значения всех ресурсов: пароли RDS, API-ключи, TLS-сертификаты. IaC-сканер проверяет
.tf-файлы, не state. Если state хранится в S3 без шифрования или с избыточным IAM-доступом - это вектор для Credentials In Files (T1552.001) и Private Keys (T1552.004). Detection: алерт на s3:GetObject к объектам *.tfstate от ролей, не входящих в whitelist.Poisoned Pipeline Execution. Атакующий модифицирует IaC-код через скомпрометированный CI/CD - Poisoned Pipeline Execution (PPE, OWASP CI/CD Top 10, CICD-SEC-04) - или внедряет вредоносный Terraform-провайдер через supply chain (T1195.001, Initial Access). IaC-сканер проверяет конфигурацию ресурсов, не поведение провайдеров. Митигация: lock-файлы зависимостей (
.terraform.lock.hcl), проверка checksums модулей, мониторинг изменений в IaC-репозиториях (T1213.003, Collection).Динамические выражения. HCL-сканер не разрешает
count, for_each, dynamic-блоки. Если security-sensitive значение вычисляется динамически - false negative. Единственная митигация - план-сканирование.
Вот что из этого следует на практике: IaC-сканер - это первая линия, не единственная. Без CSPM и SIEM-правил на drift вы закрываете только половину картины.
Detection-чеклист для SOC: корреляция IaC-событий с облачными алертами
Для SOC-команды - маппинг мисконфигураций облачной инфраструктуры на CloudTrail-события:| IaC-мисконфигурация | CloudTrail Event | Severity | MITRE ATT&CK |
|---|---|---|---|
| S3 ACL public-read/write | PutBucketAcl, PutBucketPolicy | CRITICAL | T1580 |
| IAM policy Action: * | CreatePolicy, PutRolePolicy | HIGH | T1078.004 |
| SG 0.0.0.0/0 на SSH/RDP | AuthorizeSecurityGroupIngress | HIGH | T1580 |
| RDS publicly_accessible | ModifyDBInstance | HIGH | T1580 |
| CloudTrail disabled | StopLogging, DeleteTrail | CRITICAL | T1562.008 |
| EBS volume unencrypted | CreateVolume (без KmsKeyId) | MEDIUM | T1552.001 |
| State file accessed | s3:GetObject (*.tfstate) | HIGH | T1552.001 |
| IaC repo modified | MEDIUM | T1213.003 |
Базовое корреляционное правило: если
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-конфигурации для разных облачных стеков.