实战指南:基于Ansible的Linux等保三级自动化加固方案(CentOS/Kylin)
1. 为什么你需要Ansible来做等保三级加固如果你是一名运维或者安全工程师手头管理着几十甚至上百台CentOS或者Kylin服务器每次等保检查前是不是都感觉头皮发麻一台台服务器登录上去重复执行那些繁琐又容易出错的安全加固命令改密码策略、调日志配置、设置文件权限、创建三权分立用户……这工作量想想都让人绝望。更可怕的是人工操作难免有疏漏今天这台机器忘了改SSH配置明天那台机器的审计日志没开等保测评的时候一个点没对上可能就是一次严重的合规事故。我经历过这种痛苦。早期我们团队就是靠“人肉运维”拿着一个长长的检查清单几个人分头去操作。结果呢效率低不说配置还经常不一致复查和审计更是麻烦。后来我们引入了自动化工具局面才彻底扭转。而Ansible正是解决这个问题的“神器”。它不需要在目标服务器上安装客户端Agentless仅通过SSH就能完成所有配置管理用YAML语言写“剧本”Playbook清晰易懂还能版本控制。简单来说这篇指南就是要帮你把那份零散、手动、容易出错的加固脚本变成一套标准化、可重复、可审计的自动化方案。你只需要写好一个剧本就能一键加固成百上千台服务器确保每一台的配置都严丝合缝地符合等保三级的要求。无论是CentOS 7/8还是银河麒麟KylinV10这套方案的核心思路都是相通的。接下来我就带你从零开始手把手构建这套自动化加固体系。2. 环境准备与Ansible基础工欲善其事必先利其器。在开始写加固剧本之前我们得先把“战场”布置好。这里假设你有一台可以充当“指挥中心”的管理机比如你自己的笔记本电脑或者一台跳板机系统可以是任何Linux发行版甚至macOS也行。2.1 安装与配置Ansible首先在管理机上安装Ansible。对于CentOS/RHEL系列EPEL源是最简单的选择对于Ubuntu/Debian使用apt即可。# 在CentOS/RHEL/Kylin管理机上 sudo yum install epel-release -y sudo yum install ansible -y # 在Ubuntu/Debian管理机上 sudo apt update sudo apt install ansible -y安装完成后一个关键的配置文件是/etc/ansible/ansible.cfg。我们可以创建一个项目专用的配置文件放在你的工作目录下这样更灵活。比如我们创建一个ansible.cfg文件内容如下[defaults] # 指定主机清单文件路径 inventory ./hosts # 禁用第一次连接时的主机密钥检查避免交互式确认生产环境慎用可提前分发密钥 host_key_checking False # 设置远程用户通常使用root或有sudo权限的用户 remote_user root # 设置并行执行的进程数加快批量操作速度 forks 20 # 设置SSH超时和重试应对网络波动 timeout 30 retries 3接下来我们需要定义“主机清单”Inventory告诉Ansible你要管理哪些服务器。创建一个名为hosts的文件[db_servers] 192.168.1.101 192.168.1.102 [web_servers] 192.168.1.201 ansible_useradmin # 这台服务器使用特定的用户连接 [all:vars] # 为所有主机设置通用变量 ansible_ssh_private_key_file ~/.ssh/id_rsa # 如果你的服务器密码统一也可以使用密码安全性较低 # ansible_ssh_pass YourPassword这里我创建了两个组db_servers和web_servers。等保加固通常对所有服务器都适用所以我们可以针对[all]这个组来执行剧本。现在测试一下连接是否通畅ansible all -m ping如果看到每台服务器都返回ping: pong恭喜你Ansible已经可以正常指挥你的服务器大军了。2.2 理解Ansible的核心模块与剧本Ansible的强大在于它提供了成百上千个“模块”Module每个模块就是一个专门干某件事的工具。我们等保加固最常用的几个模块是copy模块用于将本地的脚本、配置文件复制到目标服务器。lineinfile模块神器用于确保某一行文本存在于某个文件中或者修改/删除某一行。改配置文件的利器避免了用sed命令的复杂转义。command/shell模块用于执行原生的Shell命令。file模块管理文件和目录的属性比如权限、所有者。user/group模块管理用户和组。service模块管理系统服务启动、停止、重启、设置开机自启。而“剧本”Playbook就是一个YAML文件它把一系列任务Task组织起来形成一个完整的运维流程。一个任务通常就是调用一个模块。我们的目标就是把原始文章里那一大段Shell脚本拆解、翻译成一个个清晰可读的Ansible任务。3. 构建等保三级自动化加固剧本好了基础打牢现在进入核心环节编写我们的自动化加固剧本。我不会简单地把那个Shell脚本用Ansible执行一遍就完事那样失去了自动化的意义。我们要做的是用Ansible的原生模块重新实现每一项加固要求使其更健壮、更可读、具备幂等性即无论执行多少次结果都一样。我将剧本命名为hardening_playbook.yml。整个剧本会按照等保要求的逻辑模块来组织。3.1 认证与口令策略加固这是等保的基石。我们分别处理密码复杂度、生存周期、会话超时和登录失败锁定。--- - name: 等保三级 - Linux系统自动化安全加固 hosts: all # 对所有清单中的主机生效 become: yes # 使用特权权限sudo become_user: root # 切换到root用户执行 gather_facts: yes # 收集主机信息便于后续条件判断 vars: # 定义密码策略变量方便统一修改 password_minlen: 10 password_max_days: 90 password_min_days: 7 password_warn_age: 15 session_timeout: 300 login_deny: 5 unlock_time: 600 tasks: - name: 1.1 备份原始的PAM认证配置文件 copy: src: /etc/pam.d/system-auth dest: /etc/pam.d/system-auth.bak remote_src: yes # 备份远程文件 owner: root group: root mode: 0644 when: ansible_os_family RedHat # 主要针对RedHat系CentOS/Kylin - name: 1.2 设置密码复杂度策略 (pam_pwquality) lineinfile: path: /etc/pam.d/system-auth regexp: ^password\srequisite\spam_pwquality\.so line: password requisite pam_pwquality.so try_first_pass local_users_only retry3 authtok_type minlen{{ password_minlen }} lcredit-1 ucredit-1 dcredit-1 ocredit-1 enforce_for_root state: present backup: yes when: ansible_os_family RedHat - name: 1.3 设置密码生存周期 (login.defs) lineinfile: path: /etc/login.defs regexp: ^{{ item.key }} line: {{ item.key }} {{ item.value }} backup: yes with_dict: PASS_MAX_DAYS: {{ password_max_days }} PASS_MIN_DAYS: {{ password_min_days }} PASS_WARN_AGE: {{ password_warn_age }} - name: 1.4 为现有重要用户应用密码策略 command: chage -M {{ password_max_days }} -m {{ password_min_days }} -W {{ password_warn_age }} {{ item }} loop: - root - sysadmin - security - auditor ignore_errors: yes # 如果用户不存在忽略错误继续 - name: 1.5 设置会话超时自动退出 lineinfile: path: /etc/profile line: export TMOUT{{ session_timeout }} state: present insertafter: EOF backup: yes notify: # 触发一个处理程序Handler在剧本最后统一执行 - reload profile - name: 1.6 设置登录失败锁定策略 (控制台) lineinfile: path: /etc/pam.d/system-auth line: auth required pam_faillock.so preauth silent audit deny{{ login_deny }} unlock_time{{ unlock_time }} even_deny_root state: present insertafter: ^auth.*required.*pam_env.so backup: yes when: ansible_os_family RedHat # 注意CentOS 7/Kylin V10 推荐使用 pam_faillock而非旧的 pam_tally2 - name: 1.7 设置SSH登录失败锁定策略 lineinfile: path: /etc/pam.d/sshd line: auth required pam_faillock.so preauth silent audit deny{{ login_deny }} unlock_time{{ unlock_time }} even_deny_root state: present insertafter: ^auth.*substack.*password-auth backup: yes when: ansible_os_family RedHat你看用lineinfile模块来修改配置文件比在Shell脚本里写复杂的sed命令要清晰太多了。regexp参数用于定位要修改的行line参数是最终要确保存在的内容。backup: yes会在修改前自动备份原文件安全又省心。3.2 用户管理与权限控制等保三级要求实现三权分立系统管理员、安全员、审计员并严格限制root直接登录和普通用户提权。- name: 2.1 创建三权分立用户组 group: name: {{ item }} state: present loop: - sysadmin - security - auditor - name: 2.2 创建三权分立用户并设置初始密码 user: name: {{ item.name }} group: {{ item.name }} password: {{ item.password | password_hash(sha512) }} # 使用哈希密码更安全 shell: /bin/bash create_home: yes state: present loop: - { name: sysadmin, password: ChangeMe12345 } - { name: security, password: ChangeMe54321 } - { name: auditor, password: ChangeMe67890 } no_log: true # 关键不在Ansible输出中暴露明文密码 # 重要提醒上述密码仅为示例实际使用必须使用变量或Ansible Vault加密并首次登录后强制修改。 - name: 2.3 将sysadmin用户加入wheel组允许sudo user: name: sysadmin groups: wheel append: yes # 追加到现有组不覆盖 - name: 2.4 禁止Root用户通过SSH直接登录 lineinfile: path: /etc/ssh/sshd_config regexp: ^#?PermitRootLogin line: PermitRootLogin no state: present backup: yes notify: - restart sshd - name: 2.5 限制只有wheel组成员可以使用su命令切换到root lineinfile: path: /etc/pam.d/su regexp: ^#auth\srequired\spam_wheel\.so\suse_uid line: auth required pam_wheel.so use_uid state: present backup: yes when: ansible_os_family RedHat - name: 2.6 配置sudo权限限制sysadmin的权限范围 lineinfile: path: /etc/sudoers regexp: ^root\sALL\(ALL\)\sALL line: root ALL(sysadmin) ALL state: present validate: visudo -cf %s # 修改sudoers前进行语法检查防止配置错误导致sudo不可用 backup: yes这里我用了Ansible Vault的概念来提醒你密码需要加密。在实际生产环境中绝对不要把明文密码写在剧本里。应该使用ansible-vault加密变量文件或者在首次创建用户后强制用户下次登录时修改密码。3.3 系统日志与审计增强日志是安全审计的生命线。我们需要确保系统日志能持久化记录并发送到中央日志服务器同时开启系统审计服务。- name: 3.1 配置系统日志外发至日志审计服务器 blockinfile: # 使用blockinfile确保一段配置被完整添加 path: /etc/rsyslog.conf block: | # Ansible Managed - 等保三级日志外发配置 *.* 192.168.100.44:514 # 表示TCP表示UDP *.* 192.168.100.45:514 marker: # {mark} ANSIBLE MANAGED BLOCK - REMOTE LOGGING backup: yes notify: - restart rsyslog - name: 3.2 确保rsyslog服务开机自启并运行 service: name: rsyslog state: started enabled: yes - name: 3.3 确保auditd审计服务开机自启并运行 service: name: auditd state: started enabled: yes - name: 3.4 配置关键文件与操作的审计规则 copy: content: | ## 等保三级审计规则 # 监控用户删除、重命名文件 -a always,exit -F archb64 -S unlink -S unlinkat -S rename -S renameat -F auid1000 -F auid!-1 -k delete -a always,exit -F archb32 -S unlink -S unlinkat -S rename -S renameat -F auid1000 -F auid!-1 -k delete # 监控用户、组账户变更 -w /etc/passwd -p wa -k identity -w /etc/group -p wa -k identity -w /etc/shadow -p wa -k identity -w /etc/gshadow -p wa -k identity # 监控sudoers文件变更 -w /etc/sudoers -p wa -k scope -w /etc/sudoers.d/ -p wa -k scope dest: /etc/audit/rules.d/99-等保三级.rules owner: root group: root mode: 0640 notify: - reload audit rules - name: 3.5 设置历史命令记录条数 lineinfile: path: /etc/profile regexp: ^HISTSIZE line: HISTSIZE100 # 调整为合适的值原始脚本是10可能偏小 state: present backup: yes notify: - reload profileblockinfile模块非常适合用来管理配置文件中的一大段内容它会用特定的标记注释包裹起来方便后续识别和管理。审计规则的配置我选择用copy模块直接生成一个独立的规则文件这比用lineinfile在原有文件里追加更清晰也符合auditd的配置规范。3.4 文件系统与SSH服务安全这一部分涉及大量文件和目录的权限设置是防止权限提升和未授权访问的关键。- name: 4.1 设置全局umask为027 lineinfile: path: /etc/profile regexp: ^umask line: umask 0027 state: present backup: yes notify: - reload profile - name: 4.2 收紧用户家目录权限 file: path: /home/{{ item }} state: directory mode: 0750 owner: {{ item }} group: {{ item }} loop: {{ [sysadmin, security, auditor] }} ignore_errors: yes - name: 4.3 设置关键系统文件权限 file: path: {{ item.path }} owner: root group: root mode: {{ item.mode }} loop: - { path: /etc/passwd, mode: 0644 } - { path: /etc/group, mode: 0644 } - { path: /etc/shadow, mode: 0000 } # 更严格的权限 - { path: /etc/gshadow, mode: 0000 } - { path: /etc/ssh/sshd_config, mode: 0600 } - { path: /etc/hosts.allow, mode: 0644 } - { path: /etc/hosts.deny, mode: 0644 } - name: 4.4 设置SSH主机密钥文件权限 find: paths: /etc/ssh patterns: ssh_host_*_key file_type: file register: ssh_private_keys changed_when: false # 查找操作本身不触发变更 - name: 4.5 修正SSH私钥权限 file: path: {{ item.path }} owner: root group: root mode: 0600 loop: {{ ssh_private_keys.files }} loop_control: label: {{ item.path }} - name: 4.6 设置SSH最大认证尝试次数 lineinfile: path: /etc/ssh/sshd_config regexp: ^#?MaxAuthTries line: MaxAuthTries 5 state: present backup: yes notify: - restart sshd - name: 4.7 禁用不安全的SSH算法和协议 lineinfile: path: /etc/ssh/sshd_config regexp: ^{{ item.regexp }} line: {{ item.line }} state: present backup: yes loop: - { regexp: ^#?Protocol, line: Protocol 2 } - { regexp: ^#?PermitEmptyPasswords, line: PermitEmptyPasswords no } - { regexp: ^#?ClientAliveInterval, line: ClientAliveInterval 300 } - { regexp: ^#?ClientAliveCountMax, line: ClientAliveCountMax 2 } notify: - restart sshd这里展示了Ansible的loop循环可以非常高效地批量处理相似任务。find模块和register变量的结合使用能动态获取文件列表再进行操作比写死路径更灵活。3.5 定义处理程序Handlers上面很多任务都用了notify来触发“处理程序”。处理程序是一种特殊的任务只在被通知时运行一次通常用于重启服务、重载配置。handlers: - name: reload profile command: source /etc/profile # 注意source是shell内置命令不能直接用于command模块 # 更可靠的方式是让用户重新登录或者用shell模块 # 这里仅为示意实际可考虑移除或使用其他方式生效 - name: restart sshd service: name: sshd state: restarted enabled: yes - name: restart rsyslog service: name: rsyslog state: restarted enabled: yes - name: reload audit rules command: augenrules --load # 或者使用 service: nameauditd staterestarted4. 剧本执行、测试与适配剧本写好了怎么用又怎么确保它真的生效且没有副作用4.1 执行剧本与检查首先我们可以使用--check模拟运行和--diff显示更改模式来预演剧本这非常安全。# 模拟运行看哪些任务会发生变化 ansible-playbook hardening_playbook.yml --check # 模拟运行并显示具体的文件差异 ansible-playbook hardening_playbook.yml --check --diff # 确认无误后正式执行 ansible-playbook hardening_playbook.yml执行后如何验证你可以写一些简单的Ansible临时命令去检查# 检查密码策略是否生效 ansible all -m command -a grep minlen /etc/pam.d/system-auth # 检查root登录是否被禁止 ansible all -m command -a grep PermitRootLogin /etc/ssh/sshd_config # 检查审计服务状态 ansible all -m command -a systemctl status auditd4.2 处理CentOS与Kylin的差异虽然CentOS和Kylin V10同属RedHat系但细微差异仍需考虑。我们的剧本通过ansible_os_family变量和when条件语句已经做了一些适配。例如PAM模块的名称可能略有不同。更稳健的做法是将差异化的部分提取成变量或者使用ansible_distribution和ansible_distribution_major_version做更精确的判断。- name: 根据发行版安装特定软件包 yum: name: {{ item }} state: present loop: {{ security_packages }} vars: security_packages: - libselinux-utils - {{ audit if ansible_distribution CentOS else audit-libs }} # 示例逻辑4.3 日志与回滚你的安全网自动化很棒但万一剧本有bug把服务器搞坏了怎么办一定要有回滚方案。备份剧本中关键文件修改前都使用了backup: yesAnsible会在原目录下创建一个带时间戳的备份文件如system-auth.12345.2024-12-0110:00:00~。剧本版本控制使用Git管理你的Ansible Playbook每次修改都有记录可以轻松回退到上一个可用的版本。执行日志Ansible默认输出就很详细。你也可以用--log-path参数将日志输出到文件方便审计。分阶段执行不要一次性在所有生产服务器上运行全新剧本。可以先在一个测试环境或少量非关键服务器上执行验证无误后再分批应用到生产集群。我在实际推行这套方案时就建立了一个“金丝雀”服务器组。所有新剧本先在“金丝雀”组跑一遍观察一天没问题再推广到全网。这个习惯帮我避免了好几次潜在的生产事故。5. 从脚本到剧本思维升级与最佳实践看到这里你可能已经发现用Ansible写剧本不仅仅是把Shell命令“翻译”一遍。它是一种运维思维的转变从面向过程执行一串命令转向面向状态声明系统应该处于什么状态。几个我踩过坑才总结出的最佳实践变量集中管理像密码策略参数、IP地址这些一定要放在剧本开头的vars:或者独立的变量文件group_vars/,host_vars/里。改一个地方全网生效。善用标签Tags给任务打上标签比如tags: [‘password’, ‘auth’]。这样你可以只执行特定部分例如ansible-playbook hardening_playbook.yml --tags “password”非常适合调试和局部更新。角色Role化组织当剧本越来越复杂你可以将其拆分成角色。比如一个base_hardening角色负责基础安全一个等保三级角色负责合规强化一个ssh_hardening角色专门加固SSH。这样结构清晰复用性极高。密码与密钥必须加密使用Ansible Vault。把敏感信息加密后存入文件运行时通过--ask-vault-pass或 vault密码文件来解密。这是生产环境的必选项。幂等性Idempotent是生命线确保你的剧本可以安全地重复执行。Ansible绝大多数模块都是幂等的但使用command或shell模块时要格外小心确保你执行的命令本身也是幂等的比如先检查再执行。最后我想说这套自动化加固方案不是一成不变的“银弹”。等保要求、系统版本、业务场景都在变化。你需要做的是理解其精髓——用声明式的代码管理系统的安全状态。然后以这个剧本为起点结合你自身业务的特点不断迭代、优化把它变成你们团队运维体系中最坚实可靠的一环。当你下次再面对等保检查或安全巡检时你不再需要焦虑地手动登录服务器而是从容地运行一下剧本然后生成一份清晰的合规报告。这种掌控感才是自动化带来的最大价值。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2411870.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!