Рекомендации ФСТЭК по безопасной настройке Linux: ядро, права, sysctl и проверка

0
11
Обложка статьи: Рекомендации ФСТЭК по безопасной настройке Linux: ядро, права, sysctl и проверка

У ФСТЭК России есть методический документ «Рекомендации по безопасной настройке операционных систем Linux». Он не привязан к дистрибутиву и описывает конкретные параметры: права на файлы, вход root, параметры ядра. Ниже эти меры разобраны по пунктам с командами, указано, что может сломаться, и дан скрипт, который проверяет систему, ничего не меняя. Общий контекст и соответствие группам мер: hardening Linux.

Нумерация пунктов (2.1.1 … 2.6.6) дана по разбору документа на BI.ZONE (8 октября 2025). Это пересказ, а не текст документа: оригинал, его номер и действующую редакцию ищите на fstec.ru.

Для кого это обязательно

  • Для государственных информационных систем и объектов КИИ на Linux, который не сертифицирован ФСТЭК: выполнение требований обязательно до замены на сертифицированную ОС. Так это описывает BI.ZONE, уточняйте формулировку в документе.
  • Для остальных это перечень проверенных мер, не привязанный к дистрибутиву: подходит для Debian, Ubuntu, RHEL-семейства.
  • BI.ZONE приводит данные своего SOC: около 90% компаний не соблюдают хотя бы одно требование. Это данные одного вендора, но порядок величины понятен: на практике почти всегда что-то не выполнено.

Не применяйте меры на боевом сервере сразу целиком. Порядок: тестовая копия, проверка сервисов, затем боевой узел. Часть мер (ptrace, user namespaces, IOMMU, SMT) ломает конкретные сценарии.

2.1. Авторизация

Пункт Что требуется Как сделать и проверить
2.1.1 Нет учётных записей с пустым паролем: у каждого есть пароль или вход по паролю заблокирован sudo awk -F: '($2=="") {print $1}' /etc/shadow (вывод должен быть пуст). Для найденных: sudo passwd -l ИМЯ
2.1.2 Вход root по SSH запрещён PermitRootLogin no, затем sudo sshd -T | grep permitrootlogin

Остальные настройки SSH и PAM: раздел 5 общей статьи.

2.2. Ограничение получения привилегий

Пункт Что требуется Как сделать
2.2.1 Команду su могут использовать только члены группы wheel В /etc/pam.d/su строка auth required pam_wheel.so use_uid. Состав группы: getent group wheel. В Debian/Ubuntu группы wheel может не быть: создайте её (groupadd wheel) или используйте sudo
2.2.2 Ограничить, кому и какие команды разрешены через sudo Пересмотреть /etc/sudoers и /etc/sudoers.d/: sudo и sudoers

2.3. Права доступа к объектам файловой системы

Идея всех пунктов одна: файл, который исполняется с повышенными правами или влияет на вход, не должен быть изменяем посторонними, как и каталоги выше него. Ниже проверки только на чтение: сначала найдите отклонения, потом правьте осознанно.

Пункт Объект Требуемое
2.3.1 /etc/passwd, /etc/group, /etc/shadow 644, 644, и для shadow нет доступа группе и остальным (go-rwx)
2.3.2 Исполняемые файлы запущенных процессов и библиотеки Не изменяемы группой и остальными, и каталоги выше тоже
2.3.3, 2.3.6, 2.3.7 Файлы, вызываемые из cron; системные и пользовательские файлы заданий cron Нет записи для группы и остальных
2.3.4 Файлы, запускаемые через sudo Владелец root, нет записи для остальных
2.3.5 Стартовые скрипты /etc/rc*.d и файлы .service Нет записи для остальных
2.3.8 Системные утилиты и библиотеки (/bin, /usr/bin, /lib, /lib64), модули ядра /lib/modules/… Нет записи для группы и остальных
2.3.9 SUID/SGID-приложения Только нужные (по списку), без записи для остальных
2.3.10 Файлы в домашних каталогах: история команд, настройки оболочки, .rhosts Нет доступа группе и остальным (go-rwx)
2.3.11 Домашние каталоги 700

Команды поиска отклонений:

# 2.3.1 права на файлы учётных записей
stat -c '%a %U:%G %n' /etc/passwd /etc/group /etc/shadow

# 2.3.2 исполняемые файлы запущенных процессов, доступные на запись группе или остальным
for p in /proc/[0-9]*/exe; do readlink -f "$p" 2>/dev/null; done | sort -u \
  | xargs -r stat -c '%A %U %n' | awk 'substr($1,6,1)=="w" || substr($1,9,1)=="w"'

# 2.3.3, 2.3.6, 2.3.7 cron
sudo find /etc/crontab /etc/cron.* /var/spool/cron -type f -perm /022 -ls

# 2.3.5 стартовые скрипты и юниты
sudo find /etc/rc*.d /etc/systemd/system /usr/lib/systemd/system -type f -perm /002 -ls

# 2.3.8 системные каталоги и модули ядра
sudo find /bin /sbin /usr/bin /usr/sbin /lib /lib64 /usr/lib /usr/lib64 /lib/modules -xdev ! -type l -perm /022 -ls 2>/dev/null

# 2.3.9 SUID/SGID: сохраните список как эталон
sudo find / -xdev -type f \( -perm -4000 -o -perm -2000 \) -ls

# 2.3.10, 2.3.11 домашние каталоги и их файлы
stat -c '%a %n' /home/*
sudo find /home /root -maxdepth 2 -type f \( -name '.*history' -o -name '.bash*' -o -name '.profile' -o -name '.rhosts' \) -perm /077 -ls

Исправление выполняется командами вида chmod go-w ФАЙЛ, chmod 700 /home/ИМЯ, chmod -s ФАЙЛ (снять лишний SUID/SGID). Для /etc/shadow в Debian и Ubuntu штатно 640 root:shadow: приведение к 600 закрывает требование, но может нарушить работу вспомогательных программ, читающих пароли через группу shadow. Проверьте вход по SSH и sudo после правки, и держите вторую сессию открытой.

2.4. Защита ядра

Пункт Параметр Где задаётся Что делает и цена
2.4.1 kernel.dmesg_restrict=1 sysctl Журнал ядра читают только обладатели CAP_SYSLOG. Обычно безопасно
2.4.2 kernel.kptr_restrict=2 sysctl Скрывает адреса ядра в /proc. Профилировщики теряют символы
2.4.3 init_on_alloc=1 загрузка Обнуляет память при выделении. Небольшая потеря производительности
2.4.4 slab_nomerge загрузка Не объединять кэши аллокатора: усложняет эксплуатацию. Чуть больше памяти
2.4.5 iommu=force iommu.strict=1 iommu.passthrough=0 загрузка Строгая изоляция DMA. Нужна поддержка IOMMU в оборудовании, возможна потеря скорости ввода-вывода и проблемы с некоторыми устройствами
2.4.6 randomize_kstack_offset=1 (в форме on тоже) загрузка Рандомизация смещения стека ядра. Цена мала
2.4.7 mitigations=auto,nosmt загрузка Включает защиты от аппаратных уязвимостей ЦП и отключает SMT (гипертрединг). Заметно снижает производительность: проверьте нагрузку
2.4.8 net.core.bpf_jit_harden=2 sysctl Защита JIT-компилятора eBPF. Небольшая цена для BPF-программ

2.5. Сокращение периметра атаки ядра

Пункт Параметр Где Что делает и цена
2.5.1 vsyscall=none загрузка Отключает устаревший интерфейс. Ломает очень старое ПО (старые glibc)
2.5.2 kernel.perf_event_paranoid=3 sysctl Запрет событий производительности непривилегированным. Значение 3 поддерживается не всеми ядрами: если параметр не принимает 3, ставьте 2. Ломает perf без root
2.5.3 debugfs=off (или no-mount) загрузка Не монтировать debugfs. Отладка ядра становится недоступной
2.5.4 kernel.kexec_load_disabled=1 sysctl Запрет kexec. Необратим до перезагрузки. Ломает kdump
2.5.5 user.max_user_namespaces=0 sysctl Запрет пользовательских пространств имён. Ломает rootless-контейнеры (Podman, rootless Docker), Flatpak, песочницы браузеров. Проверьте заранее
2.5.6 kernel.unprivileged_bpf_disabled=1 sysctl Системный вызов bpf только для привилегированных
2.5.7 vm.unprivileged_userfaultfd=0 sysctl Запрет userfaultfd непривилегированным. Нужен некоторым ВМ и средам выполнения
2.5.8 dev.tty.ldisc_autoload=0 sysctl Не подгружать модули дисциплин линии автоматически
2.5.9 tsx=off загрузка Отключает Intel TSX. На современных ЦП обычно уже отключено
2.5.10 vm.mmap_min_addr=4096 или больше sysctl Минимальный адрес для mmap: защита от разыменования нулевого указателя
2.5.11 kernel.randomize_va_space=2 sysctl Полная рандомизация адресного пространства (ASLR)

2.6. Защита пользовательского пространства со стороны ядра

Пункт Параметр Что делает и цена
2.6.1 kernel.yama.ptrace_scope=3 Запрещает подключение к процессам через ptrace. Ломает отладчики (gdb, strace -p), и вернуть значение можно только перезагрузкой. На серверах, которые вы отлаживаете, ставьте 2
2.6.2 fs.protected_symlinks=1 Защита от атак через символические ссылки
2.6.3 fs.protected_hardlinks=1 Защита от атак через жёсткие ссылки
2.6.4 fs.protected_fifos=2 Защита записи в FIFO в общих каталогах
2.6.5 fs.protected_regular=2 То же для обычных файлов
2.6.6 fs.suid_dumpable=0 Нет дампов памяти SUID-программ

Параметры fs.protected_* по описанию не влияют на нормальную работу и блокируют только вредоносные сценарии: их можно включать сразу.

Готовые файлы настройки

Файл /etc/sysctl.d/99-fstek.conf. Закомментированы пункты с заметной ценой: включайте их осознанно.

kernel.dmesg_restrict = 1
kernel.kptr_restrict = 2
net.core.bpf_jit_harden = 2
kernel.perf_event_paranoid = 3
kernel.kexec_load_disabled = 1
kernel.unprivileged_bpf_disabled = 1
vm.unprivileged_userfaultfd = 0
dev.tty.ldisc_autoload = 0
vm.mmap_min_addr = 4096
kernel.randomize_va_space = 2
kernel.yama.ptrace_scope = 2
fs.protected_symlinks = 1
fs.protected_hardlinks = 1
fs.protected_fifos = 2
fs.protected_regular = 2
fs.suid_dumpable = 0
# ломает rootless-контейнеры, Flatpak, песочницы браузеров:
# user.max_user_namespaces = 0
# необратимо до перезагрузки, ломает отладчики:
# kernel.yama.ptrace_scope = 3
sudo sysctl --system

Параметры загрузки добавьте в GRUB_CMDLINE_LINUX:

init_on_alloc=1 slab_nomerge randomize_kstack_offset=1 vsyscall=none debugfs=off tsx=off
# отдельно, после проверки производительности и оборудования:
# iommu=force iommu.strict=1 iommu.passthrough=0
# mitigations=auto,nosmt
# Debian/Ubuntu
sudo nano /etc/default/grub && sudo update-grub
# RHEL-семейство
sudo grubby --update-kernel=ALL --args="init_on_alloc=1 slab_nomerge randomize_kstack_offset=1 vsyscall=none debugfs=off tsx=off"
sudo reboot

Если ядро не знает параметр, оно его проигнорирует: после перезагрузки проверьте результат скриптом ниже. Ошибки в параметрах загрузки могут привести к неработающей загрузке: держите консольный доступ и предыдущее ядро в меню GRUB.

Скрипт проверки (только чтение)

Сохраните как fstek-linux-check.sh. Скрипт ничего не меняет, показывает OK, FAIL или N/A (параметра нет в этом ядре) и возвращает код 1, если есть отклонения.

#!/usr/bin/env bash
# Проверка параметров ядра и загрузки по рекомендациям ФСТЭК. Ничего не изменяет.
fail=0

chk() {   # chk ПАРАМЕТР ОЖИДАЕМОЕ
  local cur
  cur=$(sysctl -n "$1" 2>/dev/null) || { printf 'N/A   %s\n' "$1"; return; }
  if [ "$cur" = "$2" ]; then printf 'OK    %s = %s\n' "$1" "$cur"
  else printf 'FAIL  %s = %s (ожидается %s)\n' "$1" "$cur" "$2"; fail=1; fi
}

chkboot() {   # chkboot ВАРИАНТ1|ВАРИАНТ2 ...
  local alt ok=0 IFS='|'
  for alt in $1; do
    case " $(cat /proc/cmdline) " in *" $alt "*) ok=1;; esac
  done
  if [ $ok = 1 ]; then printf 'OK    boot: %s\n' "$1"
  else printf 'FAIL  boot: %s\n' "$1"; fail=1; fi
}

chk kernel.dmesg_restrict 1
chk kernel.kptr_restrict 2
chk net.core.bpf_jit_harden 2
chk kernel.perf_event_paranoid 3
chk kernel.kexec_load_disabled 1
chk kernel.unprivileged_bpf_disabled 1
chk vm.unprivileged_userfaultfd 0
chk dev.tty.ldisc_autoload 0
chk kernel.randomize_va_space 2
chk kernel.yama.ptrace_scope 3
chk fs.protected_symlinks 1
chk fs.protected_hardlinks 1
chk fs.protected_fifos 2
chk fs.protected_regular 2
chk fs.suid_dumpable 0
chk user.max_user_namespaces 0
[ "$(sysctl -n vm.mmap_min_addr)" -ge 4096 ] && echo 'OK    vm.mmap_min_addr' || { echo 'FAIL  vm.mmap_min_addr'; fail=1; }

chkboot 'init_on_alloc=1'
chkboot 'slab_nomerge'
chkboot 'randomize_kstack_offset=1|randomize_kstack_offset=on'
chkboot 'vsyscall=none'
chkboot 'debugfs=off|debugfs=no-mount'
chkboot 'tsx=off'
chkboot 'iommu=force'
chkboot 'iommu.strict=1'
chkboot 'iommu.passthrough=0'
chkboot 'mitigations=auto,nosmt'

# 2.1.1, 2.1.2
[ -z "$(awk -F: '($2=="") {print $1}' /etc/shadow 2>/dev/null)" ] && echo 'OK    пустых паролей нет' || { echo 'FAIL  есть пустые пароли'; fail=1; }
sshd -T 2>/dev/null | grep -qi '^permitrootlogin no' && echo 'OK    PermitRootLogin no' || { echo 'FAIL  PermitRootLogin'; fail=1; }

exit $fail
sudo bash fstek-linux-check.sh

В скрипте ожидается ptrace_scope=3 и max_user_namespaces=0 как в документе. Если вы сознательно выбрали 2 или оставили пространства имён включёнными, это будет «FAIL»: запишите такое отклонение с причиной, а не меняйте скрипт молча.

Что ещё предлагают независимые руководства, и что из этого подходит серверу

Дополнительные меры взяты из Linux Hardening Guide Madaidan’а (последнее изменение 19 марта 2022, часть сведений могла устареть) и рекомендаций проекта KSPP. Автор прямо пишет, что руководство нельзя копировать вслепую, оно ориентировано на десктоп и строгую модель угроз. Ниже оценка применимости к серверу.

Мера Для сервера Комментарий
hidepid=2 для /proc Да Пользователи не видят чужие процессы. Требует группы proc и настройки systemd-logind (ниже)
fs.protected_*, kptr_restrict, dmesg_restrict, bpf_jit_harden Да Уже есть в документе ФСТЭК
kernel.core_pattern=|/bin/false, Storage=none в coredump.conf, * hard core 0 Да Без дампов память сервисов не утекает на диск. Но для отладки падений дампы нужны: отключайте, если у вас нет процесса их разбора
pam_wheel.so use_uid для su, блокировка root (passwd -l root) Да Первое есть в ФСТЭК. Блокировать root можно, если есть другой путь аварийного доступа (консоль, отдельный администратор)
Число раундов хеша паролей rounds=65536 Да, с оговорками Замедляет подбор. Пароли придётся сменить, чтобы они пересчитались
Сложнее политика паролей (minlen=16, difok=6) и задержка после неудачного входа (pam_faildelay, 4 с) Да Хорошо сочетается с блокировкой подбора из раздела 5 общей статьи
Блокировка модулей ядра для редких протоколов и ФС (dccp, sctp, rds, tipc, ax25, atm, cramfs, udf и др.), а также bluetooth, firewire-core, thunderbolt Да Только те, что вы не используете. nfs, cifs блокируйте, если нет сетевых дисков
Песочница systemd-служб Да, очень полезно Пример и проверка ниже
umask 0077 в /etc/profile Осторожно Для серверов с общими каталогами достаточно 027, иначе группы перестанут читать файлы друг друга
chmod 700 на /boot, /usr/src, /lib/modules Да Скрывает версию и состав ядра от непривилегированных. В Debian закрепляйте через dpkg-statoverride, иначе обновление пакетов вернёт права
vm.swappiness=1, шифрование диска (LUKS), пароль BIOS и загрузчика, Secure Boot, USBGuard По модели угроз Для серверов вне охраняемого помещения полезны. Для облачных ВМ — на стороне провайдера
lockdown=confidentiality, module.sig_enforce=1, oops=panic, init_on_free=1, page_alloc.shuffle=1 Редко Ломают DKMS-модули, отладку, имеют цену по скорости или останавливают сервер при ошибке ядра. Только после теста и если есть резервирование
net.ipv4.icmp_echo_ignore_all=1, отключение tcp_sack Нет Ломает мониторинг по ping и снижает скорость при потерях пакетов
mce=0, quiet loglevel=0 Нет Теряется диагностика аппаратных ошибок
Смена дистрибутива, musl/LibreSSL, hardened_malloc, флаги компиляции CFI, ядро linux-hardened, grsecurity Нет (для типовых задач) Меняют систему целиком или требуют пересборки ПО. Оправданы для специальных систем с отдельным процессом сопровождения
Скрытие идентификаторов (hostname, machine-id, MAC), kloak, PulseAudio, Xorg Нет Модель приватности на десктопе, а не защиты сервера

hidepid для /proc

sudo groupadd proc
# /etc/fstab
proc  /proc  proc  nosuid,nodev,noexec,hidepid=2,gid=proc  0 0
sudo mkdir -p /etc/systemd/system/systemd-logind.service.d
printf '[Service]\nSupplementaryGroups=proc\n' | sudo tee /etc/systemd/system/systemd-logind.service.d/hidepid.conf
sudo systemctl daemon-reload
sudo mount -o remount /proc
ps aux | head

Без дополнения для systemd-logind сессии пользователей могут работать некорректно. Администраторов, которым нужно видеть все процессы, добавьте в группу proc.

Ограничение службы средствами systemd

Параметры песочницы добавляются в override-файл службы (sudo systemctl edit ИМЯ). Пример для службы, которой не нужен доступ к домашним каталогам и системным файлам; подгоняйте под своё приложение, иначе оно не запустится:

[Service]
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
CapabilityBoundingSet=
SystemCallFilter=@system-service
ReadWritePaths=/var/lib/ИМЯ
sudo systemctl daemon-reload && sudo systemctl restart ИМЯ
systemd-analyze security ИМЯ

Команда systemd-analyze security показывает оценку и перечень оставшихся возможностей службы. Улучшайте оценку по одному параметру за раз, проверяя запуск. MemoryDenyWriteExecute=yes ломает приложения с JIT (Java, Node.js), поэтому его не включайте вслепую.

Как внедрять в организации

BI.ZONE справедливо отмечает: исправление конфигураций — процесс, а не разовая правка. Что из этого нужно закрепить:

  • Эталон конфигурации для каждой роли сервера: допустимые значения, исключения и порядок изменений. Хранить его в Git.
  • Согласование и журнал. Любая правка параметров проходит согласование, фиксируется кем и когда сделана.
  • Применение автоматикой, а не руками на каждом узле. Пример для Ansible:
- name: Параметры ядра по рекомендациям ФСТЭК
  ansible.posix.sysctl:
    name: "{{ item.key }}"
    value: "{{ item.value | string }}"
    sysctl_file: /etc/sysctl.d/99-fstek.conf
    reload: true
  loop: "{{ fstek_sysctl | dict2items }}"
  • Золотой образ. Безопасные настройки включайте в образ, из которого разворачиваются новые серверы, иначе старые ошибки вернутся.
  • Тест на изолированной копии и периодическая проверка соответствия скриптом выше или сканером: OpenSCAP, USG.

Как проверить результат

  1. Скрипт проверки выдаёт OK по всем пунктам, которые вы решили применять, а остальные внесены в список исключений с причиной.
  2. Команды поиска из раздела 2.3 возвращают пустой вывод (кроме эталонного списка SUID/SGID).
  3. Приложения, SSH, sudo, контейнеры и мониторинг работают так же, как до изменений.
  4. Сохранены вывод скрипта «до» и «после» и версия документа, по которому проводилась проверка.

Дальше: общий перечень по CIS, чек-лист hardening, статьи для Astra Linux и РЕД ОС, где при сертифицированной сборке часть этих параметров уже определена производителем.

Оставьте свой ответ