Рекомендации ФСТЭК по безопасной настройке 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.
Как проверить результат
- Скрипт проверки выдаёт
OKпо всем пунктам, которые вы решили применять, а остальные внесены в список исключений с причиной. - Команды поиска из раздела 2.3 возвращают пустой вывод (кроме эталонного списка SUID/SGID).
- Приложения, SSH,
sudo, контейнеры и мониторинг работают так же, как до изменений. - Сохранены вывод скрипта «до» и «после» и версия документа, по которому проводилась проверка.
Дальше: общий перечень по CIS, чек-лист hardening, статьи для Astra Linux и РЕД ОС, где при сертифицированной сборке часть этих параметров уже определена производителем.





















