- 网络安全
- 运维
- 应用安全
【免费下载链接】ansible-collection-hardening
This Ansible collection provides battle tested hardening for Linux, SSH, nginx, MySQL
本篇技术指南以 roles/os_hardening/CHANGELOG.md 为主线,梳理 devsec.os_hardening 角色从 1.0.0 到 6.3.0 的核心演进脉络,并结合本仓库中的任务源码、模板与默认变量,逐项解析 sysctl 内核加固、PAM 口令策略、auditd 审计、SUID/SGID 收敛、文件系统禁用、账户管理等关键能力。读完本文,你将理解该角色的功能全貌、关键开关变量、已知边界与常见故障排查路径,可直接用于评估与落地 Linux 基线加固。
一、CHANGELOG 全貌:版本演进主线
roles/os_hardening/CHANGELOG.md 记录了 2015-09-01 的 1.0.0 至 2020-10-28 的 6.3.0 共十余个版本,每版均按「Implemented enhancements / Fixed bugs / Closed issues / Merged pull requests」分类列出。逐版梳理可以看到三条清晰的主线:
- 平台支持不断扩张:从早期仅覆盖 Debian/RedHat 系列,逐步加入 CentOS 7(3.1)、Debian 8(3.1)、Ubuntu 18.04(5.1)、Fedora(5.2)、Amazon Linux(5.0)、Oracle 7(5.0)、OpenSUSE(6.0)、Arch(6.3),以及 Debian Buster / CentOS 8(6.0)等新版本支持。对应到 roles/os_hardening/vars 目录中按发行版拆分的
Amazon.yml、Archlinux.yml、Debian.yml、Fedora.yml、RedHat.yml、Suse.yml、Ubuntu.yml等变量文件。 - 功能从"堆砌"走向"可配置":大量 pull request 将硬编码行为改为变量驱动,典型如
os_hardening_enabled总开关(5.0)、os_auditd_enabled(5.1)、sysctl_overwrite(后续版本)、os_filesystem_whitelist、os_ignore_users等。 - 工程质量持续提升:Ansible 2.0/2.4/2.8 语法兼容、
include→import_tasks迁移、ansible-lint 接入、check mode(--check)支持(3.1)、幂等性问题修复、以find/package模块替代 shell 命令等。
这些演进在当前仓库的 roles/os_hardening/tasks 与 roles/os_hardening/defaults/main.yml 中均有落地实现,下文将逐项对证。
二、从 CHANGELOG 反推:角色到底加固了什么
2.1 功能清单(README 与 CHANGELOG 交叉印证)
roles/os_hardening/README.md 明确列出了角色的全部加固项,与 CHANGELOG 中各版本引入的功能一一对应:
- 移除不再使用的 yum 仓库并开启 GPG 校验(1.0 时代引入,yum 任务)
- 移除有已知问题的软件包(
xinetd、inetd、tftp-server、ypserv、telnet-server、rsh-server、prelink,由os_security_packages_list控制) - 配置 PAM 实现强口令校验(passwdqc / pwquality)
- 安装并配置 auditd 审计守护进程
- 通过 soft limit 禁用 core dump
- 设置严格的 umask
- 收紧系统路径中可执行文件的访问权限
- 加固 shadow 与 passwd 文件的访问
- 禁用不使用的文件系统(modprobe 黑名单)
- 禁用 rhosts
- 配置 securetty
- 通过 sysctl 配置内核参数
- 在 EL 系系统上启用 SELinux
- 移除 SUID/SGID 位
- 配置系统账户的登录与口令
注意该角色不会更新系统软件包、也不会安装安全补丁,它只做配置级加固。
2.2 任务编排:一个总开关驱动的模块化结构
roles/os_hardening/tasks/main.yml 仅做一件事——当os_hardening_enabled为真时 include hardening.yml;而 hardening.yml 则按模块逐个import_tasks,每个模块都有独立开关变量与 tag:
| 模块 | 开关变量 | tag |
|---|---|---|
| auditd | os_auditd_enabled | auditd |
| cron | os_cron_enabled | cron |
| ctrl+alt+del | os_ctrlaltdel_disabled | ctrlaltdel |
| limits | os_limits_enabled | limits |
| login_defs | os_login_defs_enabled | login_defs |
| minimize_access | os_minimize_access_enabled | minimize_access |
| PAM | os_pam_enabled | pam |
| modprobe | os_modprobe_enabled | modprobe |
| profile | os_profile_enabled | profile |
| securetty | os_securetty_enabled | securetty |
| SUID/SGID | os_security_suid_sgid_enforce | suid_sgid |
| sysctl | os_sysctl_enabled | sysctl |
| user_accounts | os_user_accounts_enabled | user_accounts |
| rhosts | os_rhosts_enabled | rhosts |
| netrc | os_netrc_enabled | netrc |
| yum | os_yum_enabled(仅 RedHat 家族) | yum |
| apt | os_apt_enabled(仅 Debian 家族) | apt |
| selinux | os_selinux_enabled(SELinux 已启用时) | selinux |
所有模块默认开启(os_*_enabled默认值均为True),可在 playbook 中按需关闭。每个模块还带独立 tag,支持ansible-playbook --tags pam之类的精细化执行。
三、版本演进中的关键能力逐项深挖
3.1 sysctl 内核加固:6.0 从 Tails 与 CIS Benchmark 吸收参数
CHANGELOG 6.0.0 提到 "Add kernel hardening parameters from Tails and CIS Benchmark"(PR #263)、"Add kernel parameter information to README"(PR #259),并修复了"容器内应用 sysctl 报错"(#243)与"检查模式下手动 touch sysctl 文件导致幂等问题"(#309/#314)等问题。
在 roles/os_hardening/defaults/main.yml 中,sysctl_config字典承载了数十个内核参数,默认值形如:
sysctl_config: fs.protected_hardlinks: 1 fs.protected_symlinks: 1 fs.protected_fifos: 1 fs.protected_regular: 2 fs.suid_dumpable: 0 kernel.core_uses_pid: 1 kernel.kptr_restrict: 2 kernel.kexec_load_disabled: 1 kernel.sysrq: 0 kernel.randomize_va_space: 2 kernel.yama.ptrace_scope: 2 net.ipv4.ip_forward: 0 net.ipv4.conf.all.rp_filter: 1 net.ipv4.tcp_syncookies: 1 net.ipv4.conf.all.accept_source_route: 0 net.ipv4.conf.all.send_redirects: 0 vm.mmap_min_addr: 65536 vm.mmap_rnd_bits: 32 vm.mmap_rnd_compat_bits: 16 ...参数大致可归为四类:
- 内核内存与执行保护:
kernel.randomize_va_space=2(ASLR 全开)、kernel.kptr_restrict=2(限制 /proc 指针可读性)、kernel.kexec_load_disabled=1、kernel.yama.ptrace_scope=2、vm.mmap_min_addr=65536(防止低地址映射攻击)、vm.mmap_rnd_bits/vm.mmap_rnd_compat_bits(mmap 随机化位数)。 - 文件系统与 SUID 保护:
fs.protected_*系列(防硬链接/软链接/管道攻击)、fs.suid_dumpable=0、kernel.core_uses_pid=1。 - IPv4 网络加固:
rp_filter反地址欺骗、tcp_syncookies、禁用accept_source_route/send_redirects/accept_redirects、icmp_echo_ignore_broadcasts、log_martians等。 - IPv6 网络加固:关闭转发、禁用
accept_ra(路由通告)、router_solicitations、autoconf等,减少邻居发现攻击面。
底层实现在 roles/os_hardening/tasks/sysctl.yml:
- 先用
file模块以state: touch、mode: 0440、modification_time: preserve方式创建/etc/sysctl.d/90-dev-sec.conf(正是 CHANGELOG 6.3.0 中 #314 用 touch 替代直接写文件、#310 保留时间戳的修复结果); - 再通过
ansible.posix.sysctl模块逐条写入,且sysctl_set: true、reload: true、ignoreerrors: true; - 关键设计:所有 sysctl 字典按
sysctl_config→sysctl_custom_config→sysctl_rhel_config(向后兼容保留)→sysctl_overwrite的顺序combine,后出现的字典覆盖先出现的键,因此用户只需在sysctl_overwrite中给出想改的参数即可,不必复制整个字典。 - 该任务仅当
ansible_facts.virtualization_type不在['docker', 'lxc', 'openvz']时执行,规避容器内无法写 sysctl 的问题(对应 #243)。
已知边界(README "Known Limitations"):
- Docker/K8s+Docker:容器内网络栈受限,必须覆盖
net.ipv4.ip_forward: 1,否则容器间转发失效:- hosts: localhost roles: - devsec.hardening.os_hardening vars: sysctl_overwrite: net.ipv4.ip_forward: 1 - vm.mmap_rnd_bits:角色默认设为
32,部分内核只支持更小值会报错,此时需覆盖为如16。
改进内核审计的建议:README 指出,auditd启动前产生的进程 AUID 为4294967295,建议在内核启动参数中加入audit=1(对应 CHANGELOG 6.0.0 的 #253),否则 auditd 日志无法完整审计所有进程。
3.2 auditd:从 5.0 引入到 6.0 可配置化
CHANGELOG 显示 auditd 于 5.0.0(#144 "install and configure auditd")引入,5.1.0 增加os_auditd_enabled开关(#192,修复无特权 LXC 上 auditd 导致失败的问题 #191),6.0.0 让max_log_file_action可配置(#246)。
roles/os_hardening/tasks/auditd.yml 的实现包含三步:
- 安装
auditd软件包(包名由auditd_package变量按发行版决定); - 渲染模板到
/etc/audit/auditd.conf(mode: 0640),变更后通知重启服务(service 与 systemd 两条 handler); - 停用并 mask
systemd-journald-audit.socket(Suse 除外,因为该发行版不存在此 socket),避免双写审计日志。
roles/os_hardening/defaults/main.yml 中os_auditd_*变量覆盖了 auditd.conf 的完整参数面,常见默认值与含义:
| 变量 | 默认值 | 说明 |
|---|---|---|
os_auditd_max_log_file | 6 | 单个日志文件最大 MB 数 |
os_auditd_max_log_file_action | keep_logs | 日志写满后的行为,常用替代为rotate |
os_auditd_num_logs | 5 | rotate时保留的日志文件数 |
os_auditd_space_left | 75 | 剩余空间低于该 MB 值触发space_left_action |
os_auditd_space_left_action | SYSLOG | 低磁盘空间动作,合法值 ignore/syslog/rotate/email/exec/suspend/single/halt |
os_auditd_admin_space_left | 50 | 更低空间阈值 |
os_auditd_admin_space_left_action | SUSPEND | 严重低空间动作 |
os_auditd_disk_full_action | SUSPEND | 磁盘写满动作 |
os_auditd_disk_error_action | SUSPEND | 写盘出错动作 |
os_auditd_flush | INCREMENTAL | 刷盘策略,可选项 none/incremental/incremental_async/data/sync |
os_auditd_log_format | RAW | 存储格式 raw/enriched |
os_auditd_name_format | NONE | 节点名插入方式 NONE/hostname/fqd/numeric |
os_auditd_log_group | root | 日志文件属组 |
os_auditd_action_mail_acct | root | email 动作的收件地址 |
3.3 PAM 口令策略:passwdqc → pwquality 与 no_pass_expiry
CHANGELOG 中 PAM 相关内容频繁出现:3.2.0 修复 RHEL7pam_passwdqc.so遗留问题并引入pam_pwquality(#73/#94)、4.3.1 实现os_security_kernel_enable_sysrq、6.0.0 修复非 RHEL 系统误建auth-system文件(#247)、以及 6.3.0 的文档改进。README 则明确按发行版采用不同 PAM 管理框架:Debian/Ubuntu 用 pam-config-framework、RHEL8 参考 authselect、RHEL6/7 参考 authconfig。
关键可配置变量(roles/os_hardening/defaults/main.yml):
os_auth_pam_passwdqc_enable(默认True):是否用 passwdqc 做强口令校验;os_auth_pam_passwdqc_options(默认min=disabled,disabled,16,12,8):passwdqc 选项串,即口令长度分级要求;os_auth_pam_pwquality_options(默认try_first_pass retry=3 authtok_type=):pwquality 模块选项;os_auth_retries(默认5):认证失败多少次后锁定账户;os_auth_lockout_time(默认600):锁定持续时间(秒);os_auth_timeout(默认60):认证超时(秒)。
实现层面,roles/os_hardening/tasks/pam.yml 会:移除pam ccreds(禁止口令缓存,防止脱离 LDAP 后仍能凭缓存登录)、按 Debian/RedHat 家族分发到 pam_debian.yml 与 pam_rhel.yml,并在 Arch 的/etc/pam.d/system-auth与 Suse 的/etc/pam.d/common-account中通过lineinfile的负向前瞻正则给pam_unix.so追加no_pass_expiry。
no_pass_expiry 的实战价值(README Known Limitations):默认 PAM 配置下,口令过期会同时阻断 SSH 密钥登录。若使用自己的 PAM 配置,应在account阶段加入pam_unix.so no_pass_expiry,典型行:
account required pam_unix.so no_pass_expiry另注意libuser.conf模板(NSA 2.3.3.5)将口令哈希算法升级为 SHA-512,且os_sha_crypt_min_rounds/os_sha_crypt_max_rounds默认均为640000,用于提高暴力破解成本(值域 1000–999999999,注意轮数越高认证 CPU 开销越大)。
3.4 SUID/SGID 收敛:从误删到白名单机制
SUID/SGID 处理是 CHANGELOG 里修复最多的领域之一:1.0 引入移除功能(#12);3.0 修复移除任务失败问题(#72/#64);5.1 将/usr/bin/su加入系统白名单(#199)并保证os_security_users_allow含change_user时 su 权限不被过度收紧(#197);5.2 修复 RHEL 7.4 "Too many setuid bits removed"(#140);6.2 将 hidepid 相关变量移入 defaults 使其可覆盖(#285)。
roles/os_hardening/tasks/suid_sgid.yml 的逻辑分两层:
- 黑名单定向移除:对
os_security_suid_sgid_system_blacklist(OS 级)与os_security_suid_sgid_blacklist(用户级)中的路径执行mode: a-s; - 未知位全局收敛(可选,
os_security_suid_sgid_remove_from_unknown默认False):用find / -xdev \( -perm -4000 -o -perm -2000 \)扫描全盘,剔除系统白名单后用set_fact取差集,再对剩余文件移除 SUID/SGID 位,用户可通过os_security_suid_sgid_whitelist保留特定文件。
相关变量:
os_security_suid_sgid_enforce(默认True):总开关;os_security_suid_sgid_remove_from_unknown(默认False):开启后会遍历已挂载文件系统,移除未在任何名单中的 SUID/SGID 位,建议在生产环境先验证白名单完整性;os_security_users_allow:可含change_user,决定是否保留 su 能力。
3.5 文件系统禁用:vfat 与 EFI 的经典坑
modprobe 模块(roles/os_hardening/tasks/modprobe.yml)默认将cramfs、freevxfs、jffs2、hfs、hfsplus、squashfs、udf、vfat(以及协议栈dccp、rds、sctp、tipc)写入/etc/modprobe.d/dev-sec.conf禁用。
CHANGELOG 中反复出现的教训:
- 5.0.0 修复 EFI/vfat 问题(#190);
- 6.2.0 "do not blacklist used filesystems"(#289)——实测禁用会导致系统不可用(5.0.0 曾出现 "System completely unresponsive after role execution",#145)。
当前实现已内置双重防护:先检测/sys/firmware/efi存在则从列表中移除vfat(EFI 引导分区通常为 vfat),再从列表中剔除ansible_facts.mounts中正在使用的文件系统类型。用户也可通过os_filesystem_whitelist(默认[])显式保留。这些设计正是对 5.0 时代 "Strongly recommend against disabling vfat by default"(#162)等问题的沉淀。
3.6 账户与口令老化:系统账户的锁定与忽略名单
roles/os_hardening/tasks/user_accounts.yml 展示了账户加固的完整链路:
- 用
getent读取 passwd/shadow 数据库; - 按 UID 区间划分:
UID > 0 且 <= os_auth_sys_uid_max归为系统账户,UID 在 [os_auth_uid_min, os_auth_uid_max]归为普通账户,UID == 0归为 root 账户; - 系统账户:shell 改为
os_nologin_shell_path、口令置为*锁定(跳过已以!开头锁定的条目,保证幂等); - 普通账户:默认设置口令老化(
password_expire_max/password_expire_warn,对应os_auth_pw_max_age默认 60 天、os_auth_pw_warn_age默认 7 天),并将家目录 chmod 0700; - root 账户:
os_rootuser_pw_ageing(默认False)控制是否同样老化;os_remove_additional_root_users(默认False)开启后删除 UID=0 且非 root 的账户。
忽略名单机制:os_ignore_users(默认['vagrant', 'kitchen'])与 OS 级os_always_ignore_users可跳过特定账户(如测试机 vagrant 用户、inspec 连接用户)。README 特别提示:使用 inspec 验证时,必须把连接用户加入os_ignore_users,否则账户会被锁定导致测试失败(对应 #124,Raspberry Pi 场景尤甚)。
此外 login_defs 模块(roles/os_hardening/tasks/login_defs.yml)渲染/etc/login.defs(mode0444),其中的UID_MIN/UID_MAX、GID_MIN/GID_MAX、SUB_UID_MIN/SUB_UID_MAX等由os_auth_uid_min(1000)、os_auth_uid_max(60000)、os_auth_sub_uid_min(100000)、os_auth_sub_uid_max(600100000)、os_auth_sub_uid_count(65536)等变量控制——这正是 CHANGELOG 6.0.0 "Make useradd defaults in login.defs dependent on OS"(#266)的成果:不同发行版使用 OS 特定 vars 中的差异化默认值。
3.7 minimize_access 与文件权限:从 shell 到 find 模块的工程化改进
CHANGELOG 5.0.0 修复 "minimize_access: maximum recursion depth exceeded on Ansible 2.5"(#171),5.2.0 大幅提速 minimize access(#208/#209),6.2.0 用find模块替代 shell(#294)并统一 when 条件(#295)。
minimize_access 将os_env_user_paths(默认/usr/local/sbin、/usr/local/bin、/usr/sbin、/usr/bin、/sbin、/bin,可经os_env_extra_user_paths追加)下文件的组/其他写权限去除,同时收紧/etc/shadow、/etc/passwd等敏感文件权限(对应 CHANGELOG 3.1 的/etc/shadow权限问题 #86 与 #89 可覆盖方案、6.3.0 的 Suse shadow 权限调整 #311)。6.3.0 还显式定义了各文件权限(#299/#300),以适配 ansible-lint 的严格要求。
3.8 其他模块速览
- limits(
os_limits_enabled):渲染 coredump 相关 soft limit 配置,os_security_kernel_enable_core_dump(默认False)控制是否允许内核 coredump,CHANGELOG 5.0.0 修复了 "Fix core dump config file creation when core dumps are disabled"(#182)。 - profile(
os_profile_enabled):设置/etc/profile.d下的环境(含TMOUT自动登出,os_security_auto_logout默认0即关闭);1.0 时代引入(#1)。 - securetty(
os_securetty_enabled):os_auth_root_ttys默认允许 root 从console, tty1-tty6登录,1.0 即支持(#2/#3)。 - rhosts / netrc:删除
~/.rhosts与~/.netrc(4.2 引入 #137),os_netrc_whitelist_user可放行指定用户。 - yum:移除未使用仓库、开启 GPG 校验(1.0 引入 #5),
os_yum_repo_file_whitelist可保护指定 repo 文件。 - selinux(6.0 引入 #154/#236):
os_selinux_state默认enforcing、os_selinux_policy默认targeted,任务在ansible_facts.selinux.status == 'enabled'且开关打开时执行。 - ufw(Debian 家族):默认 input/forward 策略 DROP、output ACCEPT,模板见 roles/os_hardening/templates/etc/default/ufw.j2,3.1 引入 "Ufw manage defaults"(#85),4.3 修复其模板 bug(#151/#152)。
四、主要故障与规避策略(CHANGELOG 修复经验汇总)
| 现象 | 版本/PR | 规避与修复 |
|---|---|---|
| 容器/无特权 LXC 上 sysctl 失败 | 6.0 (#243)、5.1 (#191) | 仅非容器环境执行 sysctl 任务;auditd 可用os_auditd_enabled=false关闭 |
| check mode 下 sysctl 文件被修改 | 6.3 (#313/#314) | 用state: touch+modification_time/access_time: preserve |
| EFI 机器禁用 vfat 后无法启动 | 5.0/6.2 (#190/#289/#162) | 检测/sys/firmware/efi、剔除已挂载文件系统,或用os_filesystem_whitelist |
| RHEL7 误删过多 SUID | 5.2 (#140) | 完善白名单;谨慎开启os_security_suid_sgid_remove_from_unknown |
| 密码过期阻断 SSH 密钥登录 | README | PAMaccount段加pam_unix.so no_pass_expiry |
vm.mmap_rnd_bits内核不支持 | README | sysctl_overwrite.vm.mmap_rnd_bits: 16 |
| inspec 连接账户被锁定 | #124 | 把连接用户加入os_ignore_users |
| RHEL7 hidepid=2 导致 systemctl 报错 | #364 | 默认hidepid_option: 0,可覆盖为2 |
| 系统账户 shell 被改后无法使用 | 设计如此 | 使用os_ignore_users/os_always_ignore_users保留需要的账户 |
五、测试与验证:molecule/inspec 佐证
本仓库用 molecule 对角色做多平台验证(molecule/os_hardening 与 molecule/os_hardening_vm),每个场景的 verify.yml 均通过verify_tasks校验加固结果。以 molecule/os_hardening/verify_tasks/pam.yml 为例,它检查 PAM 配置是否生效;molecule/os_hardening/prepare_tasks 中的netrc.yml、pw_ageing.yml、sys_account_shell.yml、ignore_home_folders.yml等则先在目标机预置"脏状态",再验证角色能正确收敛——这正是 CHANGELOG 中反复强调的"幂等性"与"check mode 兼容"的落地检验。waivers.yaml则记录已知未通过项及其原因,供 CI 持续跟踪。
六、落地建议与快速开始
最小化 playbook(roles/os_hardening/README.md):
- hosts: all become: true roles: - name: devsec.hardening.os_hardening生产落地建议:
- 先在 staging 用
--check与--diff预览变更,再执行; - Docker/K8s 环境必须设置
sysctl_overwrite.net.ipv4.ip_forward: 1; - 提前规划
os_ignore_users(部署账户、监控账户、inspec 连接用户); - 使用
sysctl_overwrite而非复制整个sysctl_config字典(更利于后续角色升级); - 若使用 EFI 引导或自用特殊文件系统,确认
os_unused_filesystems与os_filesystem_whitelist; - 开启
os_security_suid_sgid_remove_from_unknown前先在全量环境核对白名单; - 配合
audit=1内核参数提升 auditd 审计完整性。
七、结语
透过 roles/os_hardening/CHANGELOG.md 的版本记录可以看到,os_hardening 角色的演进主线是:平台覆盖扩张 → 行为变量化 → 幂等性与 check mode 兼容 → 破坏性操作加白名单护栏。每个"踩坑"都转化成了今天源码里的一个防御性判断(EFI 检测、挂载文件系统剔除、容器虚拟化类型过滤、touch 保留时间戳、no_pass_expiry等)。对使用者而言,这份演进史就是最实用的"避坑指南"——理解每个开关与默认值的来龙去脉,远比照搬默认配置更安全、更可控。
- 网络安全
- 运维
- 应用安全
【免费下载链接】ansible-collection-hardening
This Ansible collection provides battle tested hardening for Linux, SSH, nginx, MySQL
相关推荐
开机卡 Logo 不用慌:用 MTKClient 给联发科手机做完整备份与救砖的实战路线图
开机卡 Logo 不用慌:用 MTKClient 给联发科手机做完整备份与救砖的实战路线图 MTKClient 是一款面向联发科(MediaTek)芯片设备的免
网络安全运维应用安全Ansible SSH 加固实战:深入解析 ansible-collection-hardening 的 ssh_hardening 角色
Ansible SSH 加固实战:深入解析 ansible collection hardening 的 ssh_hardening 角色 导读 本文围绕开源
网络安全运维应用安全Jamstack ECommerce主题定制与样式系统:打造独特品牌体验
Jamstack ECommerce主题定制与样式系统:打造独特品牌体验 Jamstack ECommerce是一个基于Next.js和React构建高性能电子
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考