Сергей Попов

Администратор
30.12.2015
6 265
6 980
Специализация
  1. OSINT
  2. Веб-безопасность
Статус верификации
  1. ✓ Verified
Одноплатный серверный модуль на антистатическом коврике под лучом настольной лампы, на дисплее янтарным моноширинным шрифтом строка о недопустимом входе root и обнаруженном отклонении конфигурации....


Понедельник, 9:15 - SOC фиксирует успешный brute-force на SSH-порт сервера в DMZ: root-сессия активна. К 11:00 подключаюсь к постмортему. Выясняется: три недели назад при аварийных работах администратор вернул PermitRootLogin yes и не откатил. Baseline, настроенный вручную полгода назад, не пережил первого экстренного изменения. Drift не мониторился - никто не заметил. Атакующий подобрал учётные данные и зашёл под root - классическая Local Accounts (T1078.003, Initial Access). С учётом оборотных штрафов за утечку персональных данных отсутствие доказуемого baseline - не только техническая, но и юридическая дыра. Этот постмортем стал переломной точкой: харденинг серверов перестал быть документом и стал кодом.

Зачем атакующему ваш дрейф: маппинг CIS на MITRE ATT&CK

Прежде чем писать Ansible роли для безопасности, стоит разобраться - от чего именно защищаемся. Каждый контроль CIS Benchmark закрывает конкретную технику из MITRE ATT&CK. Без этого маппинга харденинг превращается в чеклист ради чеклиста, а SOC не понимает, какой алерт связан с каким контролем. Я не видел ни одного русскоязычного материала, где этот маппинг дан явно - в итоге команды раскатывают CIS Level 1 «как есть», не понимая, какую цепочку атаки разрывают.

Область харденингаКонтроль CISТехника MITRE ATT&CKТактика
SSH: запрет root-входа5.2.4Valid Accounts / Local Accounts (T1078, T1078.003)Initial Access, Persistence
Парольная политика5.4.xPassword Policy Discovery (T1201) - усложняет разведкуDiscovery
Права на /etc/shadow, /etc/passwd6.1.xCredentials In Files (T1552.001)Credential Access
Конфигурация sudo5.3.x (CIS-5 Account Management)Sudo and Sudo Caching (T1548.003)Privilege Escalation
Ограничение cron5.1.xCron (T1053.003)Execution, Persistence
Защита auditd от остановки4.1.xDisable or Modify Tools (T1562.001)Defense Evasion
Отключение лишних сервисов2.x (CIS-1 Asset Inventory)System Information Discovery (T1082) - сужает attack surfaceDiscovery

Из таблицы вытекают два практических выхода. Для Blue Team - приоритезация: если в threat model основной риск - Privilege Escalation через sudo (T1548.003), контроли CIS 5.3.x идут первыми в deployment. Для SOC - корреляция: drift в конфигурации sudo + аномальный вызов sudo -l от непривилегированного пользователя - повод для расследования, а не два несвязанных события в разных дашбордах.

CIS Controls v8 требует инвентаризации активов (CIS-1) и управления учётными записями (CIS-5), NIST SP 800-53 Rev 5 закрепляет конфигурационный менеджмент (CM-1) как обязательный элемент compliance-программы. Автоматизация харденинга Ansible покрывает оба стандарта одним pipeline.

Структура Ansible роли для харденинга серверов по CIS Benchmark​

📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме

) и область (ssh, sysctl, auditd). Запуск ansible-playbook site.yml --tags cis_level1,ssh применяет только SSH-контроли первого уровня.
YAML:
# roles/cis_baseline/tasks/ssh.yml - mitigates T1078.003
- name: "CIS 5.2.4 - Disable root login via SSH"
  ansible.builtin.lineinfile:
    path: /etc/ssh/sshd_config
    regexp: '^#?PermitRootLogin'
    line: 'PermitRootLogin no'
  when: cis_5_2_4_ssh_root_login | bool
  notify: restart sshd
  tags: [cis_level1, ssh]
Где ломается. Модуль lineinfile для sshd_config работает предсказуемо, пока в конфиге нет Match-блоков. Если PermitRootLogin задан внутри Match Address, lineinfile добавит дубль в глобальную секцию - директива сработает, но конфиг станет сложнее для аудита. Для конфигов с Match-блоками - ansible.builtin.template с полным шаблоном sshd_config.

Вторая частая боль - идемпотентность на разных дистрибутивах. Ubuntu 22.04 создаёт sshd_config с комментированными директивами (#PermitRootLogin prohibit-password), RHEL 9 - с активными. Regexp '^#?PermitRootLogin' закрывает оба варианта, но если написать без ? - playbook будет менять конфиг при каждом запуске на Ubuntu, ломая идемпотентность и генерируя ложные changed-статусы. Мелочь, но в CI/CD pipeline это красный билд на ровном месте.

Для sysctl-параметров (net.ipv4.conf.all.send_redirects, net.ipv4.tcp_syncookies) модуль ansible.posix.sysctl с reload: true стабилен. Но если в /etc/sysctl.d/ уже валяется конфликтующий файл от другого пакета - значение будет перезаписано при следующем sysctl --system. Задача-предшественник должна искать и удалять конфликты в sysctl.d/.

Аудит безопасности Ansible: compliance-проверки после применения​

Применить baseline - половина работы. Вторая - непрерывная валидация, что конфигурация не уехала. Два подхода: assert-based проверки внутри Ansible и внешний сканер OpenSCAP.

Assert-based валидация​

Отдельный playbook validate_cis.yml запускается по расписанию или после каждого change window. Каждая задача выполняет команду и через assert проверяет результат:
YAML:
- name: Check SSH config
  ansible.builtin.command: sshd -T
  register: sshd_cfg
  changed_when: false

- name: Assert root login disabled
  ansible.builtin.assert:
    that: "'permitrootlogin no' in sshd_cfg.stdout.lower()"
    fail_msg: "CIS 5.2.4 FAIL - root login permitted"
    success_msg: "CIS 5.2.4 PASS"
Обратите внимание на .lower() - sshd -T в большинстве версий OpenSSH возвращает директивы в lowercase, но на нестандартных сборках регистр может отличаться. Без .lower() проверка даст false negative, и отклонение от baseline пройдёт незамеченным. Неприятный сюрприз, если вы собрали OpenSSH из исходников.

Ограничение: assert-based подход хорош для 20–30 контролей. На полном CIS Level 2 (200+ контролей) playbook становится громоздким и тяжёлым в поддержке. Здесь нужен переход на OpenSCAP.

OpenSCAP как compliance-gate​

OpenSCAP - сканер, валидированный NIST, с SCAP-профилями под CIS и DISA STIG. Роль устанавливает openscap-scanner и scap-security-guide на managed node, запускает проверку командой oscap xccdf eval --profile cis_level1 --results /tmp/oscap-results.xml с указанием пути к XCCDF-файлу дистрибутива. Результат - XML-отчёт с verdict по каждому контролю.

Проект Compliance as Code (CaC) поддерживает автоматическую генерацию Ansible remediation-плейбуков из результатов OpenSCAP-сканирования: сканер находит отклонение, генерирует задачу Ansible, задача возвращает конфигурацию в baseline. Петля замыкается - конфигурация описана кодом, проверена сканером, исправлена кодом. Инфраструктура как код security в чистом виде.

Когда OpenSCAP подводит: профили в scap-security-guide обновляются с задержкой относительно новых релизов CIS Benchmark. Если вы перешли на RHEL 9.4, а SSG содержит профиль для 9.2 - часть проверок даст false positive. Проверяйте версию SSG через rpm -q scap-security-guide прежде чем доверять результатам. Я на этом обжёгся, когда после обновления RHEL pipeline внезапно позеленел - оказалось, SSG просто не знал про новые контроли.

Drift detection: автоматизация compliance-проверок до алерта в SIEM​

Харденинг без мониторинга - snapshot, который устаревает после первого ручного изменения. Для Blue Team критично не просто применить baseline, а знать, когда он нарушен, и видеть это в SIEM как коррелируемое событие.

Audit-правила для отслеживания конфигурационного дрейфа​

Auditd - встроенный механизм Linux для отслеживания файловых изменений. Ansible-задача деплоит правила, генерирующие событие при любой записи в критичные конфиги:
YAML:
- name: Deploy drift detection rules (T1562.001)
  ansible.builtin.copy:
    dest: /etc/audit/rules.d/hardening-watch.rules
    content: |
      -w /etc/ssh/sshd_config -p wa -k sshd_change
      -w /etc/sudoers -p wa -k sudoers_change
      -w /etc/passwd -p wa -k identity_change
      -w /etc/shadow -p wa -k identity_change
    mode: '0640'
  notify: restart auditd
Ключ -k задаёт метку, по которой SIEM фильтрует события. Администратор правит sshd_config - auditd генерирует запись с ключом sshd_change, SIEM подхватывает по key=sshd_change и создаёт алерт. Просто и надёжно.

Корреляционные правила: от drift до incident​

Одиночное изменение sshd_config - не инцидент. Но комбинация событий - повод для расследования:
  1. T1078.003 - root brute-force после drift: key=sshd_change (auditd) + в течение 15 минут новый SSH-сеанс от root (sshd log: Accepted password for root). Эта корреляция покрывает ровно тот сценарий из нашего постмортема.
  2. T1548.003 - эскалация через sudo: key=sudoers_change + в течение часа выполнение sudo от пользователя без истории sudo-вызовов (baseline поведения).
  3. T1552.001 - доступ к credential-файлам: key=identity_change на /etc/shadow + время события вне change window.
Для ELK - правило через Elastic Security Detection Rules: event.action: "opened-file" AND auditd.log.key: "sshd_change". Для Splunk - sourcetype=linux:audit key=sshd_change | stats count by host, exe. Конкретную реализацию под ваш стек придётся адаптировать, но принцип общий: auditd-метка из Ansible-роли = фильтр в корреляционном правиле SIEM.

Ограничение: auditd-правила не защищают от атакующего с root-привилегиями, который может остановить auditd (T1562.001, Disable or Modify Tools). Контрмера: параметр ядра audit=1 в GRUB и --loginuid-immutable в правилах auditd - оба контроля должны быть в Ansible-роли как задачи CIS 4.1.x. Без них вся цепочка drift detection рассыпается.

CI/CD pipeline для непрерывного аудита безопасности​

Compliance-проверки, запускаемые вручную, работают ровно до момента, когда у команды заканчивается время. А оно заканчивается всегда. DevSecOps-подход: харденинг встраивается в CI/CD pipeline.

Pipeline из трёх стадий: lint → test → deploy. На стадии lint - ansible-lint с правилами идемпотентности (rule 301: Commands should not change things) и FQCN-модулей (rule 206). Lint не пройден - merge request заблокирован. На стадии test - Molecule поднимает контейнер с целевым дистрибутивом, применяет роль, затем запускает validate_cis.yml. Assert-проверки падают - pipeline красный. На стадии deploy - ansible-playbook site.yml --diff --check сначала в dry-run на staging, затем после ручного approve - на production. Флаг --diff показывает конкретные строки, которые изменятся в конфигах - точка ревью для security-инженера.

GitLab CI поддерживает schedules: validate_cis.yml - ежедневно, полный site.yml --check - еженедельно, enforce site.yml - после каждого change window. Даже если кто-то изменил конфиг вручную - следующий scheduled run вернёт baseline.

Ограничение Molecule с Docker: контейнеры по умолчанию не запускают systemd. Handler'ы restart sshd и restart auditd пройдут lint, но не будут протестированы. Для полноценного теста systemd-зависимых задач нужен Molecule с драйвером Vagrant или Podman в --privileged режиме. Без этого вы тестируете половину роли и надеетесь на лучшее.

Половина инцидентов, которые я разбирал за последний год, начинались не с эксплойта нулевого дня, а с ручного изменения конфига, которого никто не заметил. Временный PermitRootLogin yes, забытый net.ipv4.ip_forward = 1, отключённый auditd «на время дебага». CIS Benchmark в виде PDF не умеет откатывать изменения и не отправляет алерт. Работает только связка «код + валидация + мониторинг»: Ansible как движок, OpenSCAP как аудитор, auditd + SIEM как сигнализация.

Скажу непопулярную вещь: в большинстве команд compliance as code живёт в репозитории, который никто не трогает после первого коммита. Роль написана, pipeline зелёный - и всё. Через полгода SSG-профиль устарел, Molecule-тесты не проходят на новой версии Python, в production добавились дистрибутивы, которых нет в inventory. Реальная зрелость compliance-автоматизации измеряется не первым деплоем, а количеством коммитов в роль за квартал. Ноль коммитов за три месяца - baseline уже дрейфует, просто тихо. Если в вашем SIEM пока нет правил под drift detection из auditd - на codeby.net в тематическом треде по compliance-автоматизации коллеги делятся работающими корреляциями под разные платформы.
 
Мы в соцсетях:

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

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🧭 Навигатор · ИБ 2026
Не знаешь, какой трек твой?
5 направлений ИБ, реальные зарплаты и точка входа для каждого — в одном треде.
JuniorSenior+
100K → 600K+ ₽ /мес
Открыть навигатор →

Популярный контент

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

HackerLab