githubixx.harden_linux
加固 Linux 的 Ansible 角色
这个 Ansible 角色主要是为我的博客系列 Kubernetes 的简单方法与 Ansible - 加固实例 创建的。当然,它也可以独立使用来加固 Linux。它具有以下功能(其中一些是可选的):
- 添加一个用于管理的常规/部署用户(例如,用于 Ansible 或 SSH 登录)
- 调整 APT 更新间隔
- 设置
UFW
防火墙,默认只允许 SSH 访问(如果需要,可以添加更多规则/允许的网络) - 调整与安全相关的 sysctl 设置
- 调整
sshd
设置,例如禁用 sshd 密码认证,禁用 sshd 根用户登录,禁用 sshd PermitTunnel - 安装
sshguard
并调整白名单 - 更改根用户密码
- 安装/配置
网络时间同步
(NTP),例如openntpd
/ntp
/systemd-timesyncd
- 修改
systemd-resolved
配置
版本
我为每个版本打上标签,并努力遵循 语义化版本控制。如果你想使用这个角色,我建议你查看最新的标签。主分支基本上是开发,而标签标记稳定版本。但一般来说,我也会尽量保持主分支的良好状态。
更新日志
变更历史:
查看完整的 CHANGELOG.md
最近更改:
v8.2.0
- 新特性
- 支持 Ubuntu 24.04
v8.1.0
其他
- 更新关于使用
mkpasswd
而不是ansible
创建加密密码的注释 - Ubuntu: 添加自动删除任务
- 更新 Github 工作流
- 更新关于使用
MOLECULE
- 使用
alvistack
替代generic
Vagrant box - 使用不同的 IP 地址
- 使用
v8.0.0
重大更新/新特性
- 引入
harden_linux_deploy_group
和harden_linux_deploy_group_gid
变量。两者都是可选的。但至少harden_linux_deploy_group
必须在harden_linux_deploy_user
设定的情况下被指定。如果设置为root
,则不会有任何更改。 - 如果
harden_linux_deploy_user
设定为root
,则不会有任何更改。 harden_linux_deploy_user
现在是可选的。如果未设定,将不会创建用户。所有以harden_linux_deploy_user_
开头的变量仅在harden_linux_deploy_user
被指定时使用。另添加了harden_linux_deploy_user_home
变量,harden_linux_deploy_user_shell
、harden_linux_deploy_user_home
、harden_linux_deploy_user_uid
和harden_linux_deploy_user_password
现在都是可选的。harden_linux_deploy_user
的 $HOME 目录仅在设置了harden_linux_deploy_user_home
时创建。
- 引入
MOLECULE
- 更新测试场景以反映部署用户/组更改
安装
从 Github 直接下载(在克隆之前切换到 Ansible 角色目录。可以使用
ansible-config dump | grep DEFAULT_ROLES_PATH
命令找出角色路径):git clone https://github.com/githubixx/ansible-role-harden-linux.git githubixx.harden_linux
通过
ansible-galaxy
命令直接从 Ansible Galaxy 下载:ansible-galaxy install role githubixx.harden_linux
创建一个
requirements.yml
文件,内容如下(这将从 Github 下载角色),然后使用ansible-galaxy role install -r requirements.yml
安装(如有需要,请更改version
):
---
roles:
- name: githubixx.harden_linux
src: https://github.com/githubixx/ansible-role-harden-linux.git
version: v8.1.0
角色变量
以下变量没有默认值。您需要在 group_vars
或 host_vars
目录中的文件中指定它们。例如,如果这些设置仅适用于一个特定主机,请为该主机创建一个文件,文件名与该主机的完全限定域名相同(例如 host_vars/your-server.example.tld
),并在那里添加变量及其正确值。如果您想将这些变量应用于一个主机组,请创建一个文件 group_vars/your-group.yml
,例如用该主机组名称替换 your-group
(请不要与 /etc/hosts 混淆)。
如果您想设置或更改 root
用户的密码,请设置 harden_linux_root_password
变量。这是可选的。它期望一个加密密码。Ansible 不会为您加密密码。如何创建加密密码可参考 Ansible 常见问题解答。在 Linux 上,以下命令可能是最可靠的:
mkpasswd --method=sha-512
要安装一个可以无密码执行 sudo
的用户,请设置以下变量:
harden_linux_deploy_user: "a_username"
harden_linux_deploy_user_password: "a_password"
harden_linux_deploy_user_home: "/home/a_user"
harden_linux_deploy_user_uid: "9999"
harden_linux_deploy_user_gid: "9999"
harden_linux_deploy_user_shell: "/bin/bash"
harden_linux_deploy_user
指定我们要用于登录远程主机的用户。如前所述,harden_linux
角色将出于合理原因禁用根用户通过 SSH 登录。因此需要一个不同的用户。这个用户将被授予 "sudo" 权限,这对 Ansible(和/或您自己)完成工作是必需的。
在 harden_linux_deploy_user_password
中存储用户的加密密码。与 harden_linux_root_password
相关的内容同样适用。
用户的 $HOME 目录在 harden_linux_root_password
中指定。要设置 UID 和 GID,请使用 harden_linux_deploy_user_uid
和 harden_linux_deploy_user_gid
。注意:如果用户已存在但具有不同的主目录、UID 和/或 GID,它将根据上述设置进行更改!这也适用于指定用户登录后应该使用的 shell 的 harden_linux_deploy_user_shell
。
harden_linux_deploy_user_public_keys
指定一个公钥 SSH 文件列表,您希望将其添加到远程主机上部署用户的 $HOME/.ssh/authorized_keys
中。如果您在这里指定 /home/deploy/.ssh/id_rsa.pub
,则该本地文件的内容(在 Ansible 控制节点上)将被添加到远程主机上的部署用户的 $HOME/.ssh/authorized_keys
中。
harden_linux_optional_packages
(在该角色的 v6.0.0 版本之前此变量被称为 harden_linux_required_packages
)指定要在远程主机上安装的其他/可选软件包。默认情况下此变量未指定。例如:
harden_linux_optional_packages:
- vim
与前面的变量相对, harden_linux_absent_packages
将卸载远程主机上的 OS 软件包。默认情况下此变量未指定。例如:
harden_linux_absent_packages:
- vim
以下变量具有默认值。因此只有在需要其他值时才需要更改它们。角色默认更改一些 sshd
设置:
harden_linux_sshd_settings:
"^PasswordAuthentication": "PasswordAuthentication no" # 禁用密码认证
"^PermitRootLogin": "PermitRootLogin no" # 禁用 SSH 根登录
"^PermitTunnel": "PermitTunnel no" # 禁用 tun(4) 设备转发
"^Port ": "Port 22" # 设置 sshd 端口
我个人总是更改默认 SSH 端口,因为很多暴力破解攻击发生在此端口(但当然,端口扫描器仍然能够快速找出这一点)。因此,如果您想更改端口设置,可以例如这样做:
harden_linux_sshd_settings_user:
"^Port ": "Port 22222"
(请注意 ^Port
后的空格!)。该剧本将合并 harden_linux_sshd_settings
和 harden_linux_sshd_settings_user
,而 harden_linux_sshd_settings_user
中的设置优先,这意味着它将覆盖 harden_linux_sshd_settings
中的 ^Port
设置/键。正如您可能已经注意到的,harden_linux_sshd_settings
和 harden_linux_sshd_settings_user
中的所有键都以 ^
开头。这是因为它是一个正则表达式 (regex)。剧本中的一个任务将搜索 /etc/ssh/sshd_config
中的某行,例如 ^Port
(而 ^
表示“以...开头的行”),并用例如 Port 22222
替换该行(如果找到)。这种方式使剧本在调整 sshd_config
中的设置时非常灵活(您基本上可以替换每个设置)。您也会看到其他任务中有这种模式。所以在这种情况下所有提到的内容都成立。
接下来是一些防火墙/iptables 的默认设置。防火墙/iptables 规则和设置由 UFW 管理:
harden_linux_ufw_defaults:
"^IPV6": 'IPV6=yes'
"^DEFAULT_INPUT_POLICY": 'DEFAULT_INPUT_POLICY="DROP"'
"^DEFAULT_OUTPUT_POLICY": 'DEFAULT_OUTPUT_POLICY="ACCEPT"'
"^DEFAULT_FORWARD_POLICY": 'DEFAULT_FORWARD_POLICY="DROP"'
"^DEFAULT_APPLICATION_POLICY": 'DEFAULT_APPLICATION_POLICY="SKIP"'
"^MANAGE_BUILTINS": 'MANAGE_BUILTINS=no'
"^IPT_SYSCTL": 'IPT_SYSCTL=/etc/ufw/sysctl.conf'
"^IPT_MODULES": 'IPT_MODULES="nf_conntrack_ftp nf_nat_ftp nf_conntrack_netbios_ns"'
这些设置基本上是更改 /etc/defaults/ufw
中的值。要覆盖一个或多个默认设置,您可以通过指定上述相同的键(这是一个正则表达式)来做到这一点,例如 ^DEFAULT_FORWARD_POLICY
并简单地分配一个新值:
harden_linux_ufw_defaults_user:
"^DEFAULT_FORWARD_POLICY": 'DEFAULT_FORWARD_POLICY="ACCEPT"'
如前所述,该剧本还将合并 harden_linux_ufw_defaults
和 harden_linux_ufw_defaults_user
,而 harden_linux_ufw_defaults_user
中的设置优先。
接下来我们可以使用 harden_linux_ufw_rules
指定一些防火墙规则。默认情况下允许在端口 22
上进行 SSH 流量(使用 TCP 协议):
harden_linux_ufw_rules:
- rule: "allow"
to_port: "22"
protocol: "tcp"
以下参数可用,具有默认值(如有):
rule (无默认值)
interface (默认 '')
direction (默认 'in')
from_ip (默认 'any')
to_ip (默认 'any')
from_port (默认 '')
to_port (默认 '')
protocol (默认 'any')
log (默认 'false')
delete (默认 'false')
一个 规则 可以具有值 allow
、deny
、limit
和 reject
。interface 指定规则的接口。direction(in
或 out
)用于接口,依据方向的值而定。from_ip 指定源 IP 地址, from_port 指定源端口。to_ip 指定目标 IP 地址, to_port 指定目标端口。protocol 默认为 any
。可能值为 tcp
、udp
、ipv6
、esp
、ah
、gre
和 igmp
。log 可以是 false
(默认)或 true
,指示是否应记录匹配该规则的新连接。delete 指示是否应删除规则。如果之前添加的规则需要被移除,那么这就很重要。仅从 harden_linux_ufw_rules
中移除规则是不够的!您必须使用 delete
删除该规则。
您还可以允许主机在特定网络上进行通信(没有端口限制),例如:
harden_linux_ufw_allow_networks:
- "10.3.0.0/24"
- "10.200.0.0/16"
接下来,harden_linux
角色还会更改某些系统变量(sysctl.conf / proc 文件系统)。这些设置是 Google 的建议,他们在 Google Compute Cloud OS 镜像中使用这些设置(请参阅 Google Cloud - 构建自定义映像的要求 和 配置与 Compute Engine 导入的映像)。以下是默认设置(如果您对这些设置满意,则无需做任何事情,但我建议验证它们是否适用于您的设置):
harden_linux_sysctl_settings:
"net.ipv4.tcp_syncookies": 1 # 启用 syn flood 保护
"net.ipv4.conf.all.accept_source_route": 0 # 忽略源路由的数据包
"net.ipv6.conf.all.accept_source_route": 0 # IPv6 - 忽略 ICMP 重定向
"net.ipv4.conf.default.accept_source_route": 0 # 忽略源路由的数据包
"net.ipv6.conf.default.accept_source_route": 0 # IPv6 - 忽略源路由的数据包
"net.ipv4.conf.all.accept_redirects": 0 # 忽略 ICMP 重定向
"net.ipv6.conf.all.accept_redirects": 0 # IPv6 - 忽略 ICMP 重定向
"net.ipv4.conf.default.accept_redirects": 0 # 忽略 ICMP 重定向
"net.ipv6.conf.default.accept_redirects": 0 # IPv6 - 忽略 ICMP 重定向
"net.ipv4.conf.all.secure_redirects": 1 # 忽略来自非网关主机的 ICMP 重定向
"net.ipv4.conf.default.secure_redirects": 1 # 忽略来自非网关主机的 ICMP 重定向
"net.ipv4.ip_forward": 0 # 不允许网络间的流量或作为路由器
"net.ipv6.conf.all.forwarding": 0 # IPv6 - 不允许网络间的流量或作为路由器
"net.ipv4.conf.all.send_redirects": 0 # 不允许网络间的流量或作为路由器
"net.ipv4.conf.default.send_redirects": 0 # 不允许网络间的流量或作为路由器
"net.ipv4.conf.all.rp_filter": 1 # 反向路径过滤 - IP 欺骗保护
"net.ipv4.conf.default.rp_filter": 1 # 反向路径过滤 - IP 欺骗保护
"net.ipv4.icmp_echo_ignore_broadcasts": 1 # 忽略 ICMP 广播以避免参与 Smurf 攻击
"net.ipv4.icmp_ignore_bogus_error_responses": 1 # 忽略错误 ICMP 错误
"net.ipv4.icmp_echo_ignore_all": 0 # 忽略错误 ICMP 错误
"net.ipv4.conf.all.log_martians": 1 # 记录伪造、源路由以及重定向的数据包
"net.ipv4.conf.default.log_martians": 1 # 记录伪造、源路由以及重定向的数据包
"net.ipv4.tcp_rfc1337": 1 # 实施 RFC 1337 修复
"kernel.randomize_va_space": 2 # 随机化 mmap 基址、堆、栈以及 VDSO 页面的地址
"fs.protected_hardlinks": 1 # 提供对 ToCToU 竞赛条件的保护
"fs.protected_symlinks": 1 # 提供对 ToCToU 竞赛条件的保护
"kernel.kptr_restrict": 1 # 使定位内核地址更加困难
"kernel.perf_event_paranoid": 2 # 仅 root 可用 perf
您可以通过创建一个名为 harden_linux_sysctl_settings_user
的变量来覆盖每个单独的设置:
harden_linux_sysctl_settings_user:
"net.ipv4.ip_forward": 1
"net.ipv6.conf.default.forwarding": 1
"net.ipv6.conf.all.forwarding": 1
剧本中的一个任务将合并 harden_linux_sysctl_settings
和 harden_linux_sysctl_settings_user
,而 harden_linux_sysctl_settings_user
的设置将优先。有关设置的更多信息,请查看角色的 defaults/main.yml
文件。
如果您想启用 UFW 日志记录,请设置:
harden_linux_ufw_logging: 'on'
可能值为 on
、off
、low
、medium
、high
和 full
。
接下来是 “sshguard” 设置。“sshguard” 保护免受对 SSH 的暴力破解攻击。为了避免一段时间内将自己锁定,您可以将 IP 或 IP 范围添加到白名单。默认情况下,它基本上只有“localhost”:
harden_linux_sshguard_whitelist:
- "127.0.0.0/8"
- "::1/128"
NTP 软件包也可以安装/配置。这是可选的。默认情况下,我建议使用 systemd-timesyncd
。您也可以使用 ntp
软件包。但 openntpd
和 systemd-timesyncd
的优势在于它们默认不监听任何端口。如果您只想保持主机时钟同步,这完全足够。确保所有主机上的时间一致对某些服务至关重要。例如,用于证书验证、etcd、数据库、加密等。
有效的 harden_linux_ntp
选项是:
- openntpd
- ntp
- systemd-timesyncd
正如前面提到的,openntpd
和 systemd-timesyncd
的优势在于它们默认不监听任何端口。如果您只想保持主机时钟同步,这两个中的任何一个应该可以完成工作。大多数现代 Linux 操作系统都使用 systemd
,所以在这种情况下无需安装额外的软件包。要启用 openntpd
,请相应设置 harden_linux_ntp
,例如:
harden_linux_ntp: "openntpd"
openntpd
、ntpd
或 systemd-timesyncd
的设置(见下一段)。有关进一步的选项,请查看手册页:man 5 ntpd.conf
适用于 ntp
和 openntpd
,man 5 timesyncd.conf
适用于 systemd-timesyncd
。
“关键”是您想要替换的设置的正则表达式,以及设置名称和设置值的组合。例如,我们想将 servers 0.debian.pool.ntp.org
替换为 servers 1.debian.pool.ntp.org
。正则表达式(键)将是 ^servers 0
,这意味着:
“在配置文件中搜索以 server 0
开头的行,将整行替换为 servers 1.debian.pool.ntp.org
”。通过这种方式,可以将配置文件中的每个设置替换为其他东西。一些示例:
harden_linux_ntp_settings:
"^servers 0": "servers 0.debian.pool.ntp.org"
"^servers 1": "servers 1.debian.pool.ntp.org"
"^servers 2": "servers 2.debian.pool.ntp.org"
"^servers 3": "servers 3.debian.pool.ntp.org"
请注意:systemd-timesyncd
具有合理的编译时默认值。因此,通常无需更改配置(连 NTP 服务器也不需要)。因此,以下只是示例,但在实际情况下,您不需要为 systemd-timesyncd
指定 harden_linux_ntp_settings
。
对于 systemd-timesyncd
,配置文件略有不同。在这种情况下,/etc/systemd/timesyncd.conf
的 systemd drop-in 将创建在 /etc/systemd/timesyncd.conf.d/
中。
Debian 示例:
harden_linux_ntp_settings:
"^#NTP=": "NTP=0.debian.pool.ntp.org 1.debian.pool.ntp.org 2.debian.pool.ntp.org 3.debian.pool.ntp.org"
Ubuntu 示例:
harden_linux_ntp_settings:
"^#NTP=": "NTP=ntp.ubuntu.com"
Archlinux 示例:
harden_linux_ntp_settings:
"^#NTP=": "NTP=0.arch.pool.ntp.org 1.arch.pool.ntp.org 2.arch.pool.ntp.org 3.arch.pool.ntp.org"
使用 harden_linux_files_to_delete
,可以指定一个文件列表,这些文件应在目标主机上不存在,例如:
harden_linux_files_to_delete:
- "/root/.pw"
如果使用 systemd-resolved
进行 DNS 解析,可以通过 harden_linux_systemd_resolved_settings
调整其行为。默认情况下未指定此变量。将在 /etc/systemd/resolved.conf.d/99-override.conf
中创建 systemd drop-in 配置,并将指定的设置添加到那里。
注意:如果 /etc/systemd/resolved.conf
中已经设置了某个设置(例如 DNS=8.8.8.8
),则在下面设置 DNS=9.9.9.9
将一起生效。这意味着最终设置将是 DNS=8.8.8.8 9.9.9.9
。如果您不希望这样,您需要先“取消设置”该值,然后再添加您想要的新值。例如:
harden_linux_systemd_resolved_settings:
- DNS=
- DNS=9.9.9.9
虽然 Google DNS 服务器(8.8.8.8
、8.8.4.4
)提供快速的 DNS 查找,但当然这也是 Google 可以监视您的另一种可能性。因此,使用一些其他的 DNS 服务器至少应该是一个需要考虑的事情。但还有一点是加密 DNS 请求。systemd-resolved
支持的一个方式是 DNSOverTLS
。 Quad9 (9.9.9.9/149.112.112.112) 和 Cloudflare (1.1.1.1/1.0.0.1) 支持 DNSOverTLS
。
因此,以下 systemd-resolved
设置为 Quad9 和 Cloudflare DNS 配置 IPv4 和 IPv6。设置 DNSOverTLS=opportunistic
使用 DNSOverTLS
,如果 DNS 服务器支持它,则回退到普通未加密 DNS(详见 resolved.conf.5):
harden_linux_systemd_resolved_settings:
- DNS=
- DNS=9.9.9.9 1.1.1.1 2606:4700:4700::1111 2620:fe::fe
- FallbackDNS=
- FallbackDNS=149.112.112.112 1.0.0.1 2620:fe::9 2606:4700:4700::1001
- DNSOverTLS=
- DNSOverTLS=opportunistic
此外,还可以影響软件包管理器的缓存行为。例如,对于 Ubuntu:
# 如果不希望更新软件包缓存,则将其设置为 "false"
harden_linux_ubuntu_update_cache: true
# 设置软件包缓存有效时间
harden_linux_ubuntu_cache_valid_time: 3600
对于 Archlinux:
# 如果不希望更新软件包缓存,则将其设置为 "false"
harden_linux_archlinux_update_cache: true
示例剧本
如果您通过 ansible-galaxy install githubixx.harden_linux
安装了角色,则可以像以下示例那样将角色包含到您的剧本中:
- hosts: webservers
roles:
- githubixx.harden_linux
测试
该角色具有一个小型测试设置,使用 Molecule、libvirt (vagrant-libvirt) 和 QEMU/KVM 创建。请查看我的博客文章 使用 Molecule、libvirt (vagrant-libvirt) 和 QEMU/KVM 测试 Ansible 角色 了解如何设置。测试配置在 这里 。
然后可以执行 molecule:
molecule converge
这将在支持的不同 Linux 操作系统上设置几个虚拟机 (VM),并相应地设置 harden_linux
角色。还包括一个小的验证步骤:
molecule verify
要清理,请运行:
molecule destroy
许可
GNU 通用公共许可证 第 3 版
作者信息
Ansible role for hardening Linux
ansible-galaxy install githubixx.harden_linux