iT邦幫忙

2025 iThome 鐵人賽

DAY 27
0
DevOps

不爆肝學習 Ansible 的短暫30天系列 第 27

Day27 - Ansible 的安全強化與法規遵循

  • 分享至 

  • xImage
  •  

今日目標

  • 了解為什麼自動化安全管理如此重要
  • 掌握使用 Ansible 實施 CIS Benchmark 安全基線
  • 學會設計完整的安全加固 Playbook
  • 建立自動化合規檢查和報告機制

舉個例子:為什麼安全不能只靠人工?

假設某家公司的系統管理員每次新建伺服器時,都需要手動執行一份「安全檢查清單」來關閉不必要的服務、設定防火牆規則、調整 SSH 設定等等...

這看起來很完美對吧?

但現實是:

  • 🚨 人為疏失:某次忘記關閉 Telnet 服務,結果被駭客入侵
  • 時間壓力:趕專案時跳過某些安全步驟,「等有時間再補」
  • 📋 標準不一:不同管理員執行的安全標準略有差異
  • 🔍 難以稽核:無法快速確認所有伺服器的安全狀態

這就是為什麼我們需要 Security as Code,讓安全配置像程式碼一樣可重複、可驗證、可版控。

💡Tips:資訊安全從來不是靠人的記憶力,而是具有規範的執行,但由於手動執行絕對會有誤差,所以我們需要導入自動化,每一次的操作都是一樣且具可追朔性的。

為什麼選擇 Ansible 做安全自動化?

經過這幾年的實務經驗,筆者認為 Ansible 在安全自動化領域有幾個獨特優勢:

  1. 無代理架構:不需要在目標主機安裝額外軟體,減少攻擊面
  2. 冪等性保證:重複執行不會造成配置錯誤,適合定期安全檢查
  3. 豐富的安全模組:內建 firewalld、SELinux、user 等安全相關模組
  4. 可讀性高:安全政策用 YAML 描述,非技術人員也能理解
  5. 社群支持:有現成的 CIS Benchmark 和各種安全 Role 可以使用

當然,市面上也有其他優秀的工具如 Chef、Puppet,但 Ansible 的學習曲線相對平緩,非常適合 DevOps 團隊快速上手。

CIS Benchmark 是什麼?

CIS (Center for Internet Security) Benchmark 是業界公認的安全配置基準,涵蓋作業系統、資料庫、網頁伺服器等各種系統的安全設定建議。
以 Ubuntu 為例,CIS Benchmark 包含了 200+ 項安全檢查項目,分為:

  • Level 1:基本安全要求,適合所有環境
  • Level 2:進階安全要求,可能影響功能性

讓我們來看看如何用 Ansible 實現這些安全基線!

建立安全基線 Role

首先建立一個專門的安全 Role 結構:

mkdir -p roles/security_hardening/{tasks,handlers,templates,defaults,files}

預設變數配置

---
# roles/security_hardening/defaults/main.yml

# SSH 安全設定
ssh_port: 22
ssh_permit_root_login: false
ssh_password_authentication: false
ssh_max_auth_tries: 3
ssh_client_alive_interval: 300
ssh_client_alive_count_max: 2

# 防火牆設定
firewall_enabled: true
firewall_default_policy: "DROP"
firewall_allowed_ports:
  - "{{ ssh_port }}/tcp"
  - "80/tcp"
  - "443/tcp"

# 用戶和權限設定
admin_users:
  - name: "deploy"
    groups: ["sudo", "adm"]
    shell: "/bin/bash"
  - name: "monitoring"
    groups: ["adm"]
    shell: "/bin/bash"

# 系統安全參數
kernel_parameters:
  # 網路安全
  - name: "net.ipv4.ip_forward"
    value: "0"
  - name: "net.ipv4.conf.all.send_redirects"
    value: "0"
  - name: "net.ipv4.conf.default.send_redirects"
    value: "0"
  - name: "net.ipv4.conf.all.accept_redirects"
    value: "0"
  - name: "net.ipv4.conf.default.accept_redirects"
    value: "0"
  # 記憶體保護
  - name: "kernel.dmesg_restrict"
    value: "1"
  - name: "kernel.kptr_restrict"
    value: "2"

# 日誌和監控
log_retention_days: 90
audit_enabled: true
fail2ban_enabled: true

# 合規檢查
cis_level: "1"  # 1 或 2
generate_compliance_report: true

主要任務

---
# roles/security_hardening/tasks/main.yml
- name: 載入 OS 特定變數
  include_vars: "{{ ansible_distribution }}.yml"
  ignore_errors: yes

- name: 系統更新和基本安全
  include_tasks: system_updates.yml
  tags: ['system', 'updates']

- name: SSH 服務安全加固
  include_tasks: ssh_hardening.yml
  tags: ['ssh', 'network']

- name: 防火牆配置
  include_tasks: firewall.yml
  tags: ['firewall', 'network']

- name: 用戶和權限管理
  include_tasks: user_management.yml
  tags: ['users', 'permissions']

- name: 核心參數調整
  include_tasks: kernel_hardening.yml
  tags: ['kernel', 'system']

- name: 服務安全配置
  include_tasks: service_hardening.yml
  tags: ['services']

- name: 日誌和監控設定
  include_tasks: logging_monitoring.yml
  tags: ['logging', 'monitoring']

- name: 安全掃描和合規檢查
  include_tasks: compliance_check.yml
  tags: ['compliance', 'audit']
  when: generate_compliance_report | bool

SSH 安全強化實作

---
# roles/security_hardening/tasks/ssh_hardening.yml
- name: 備份原始 SSH 配置
  copy:
    src: /etc/ssh/sshd_config
    dest: /etc/ssh/sshd_config.backup.{{ ansible_date_time.epoch }}
    remote_src: yes
    backup: yes
  tags: ['backup']

- name: 生成安全的 SSH 配置
  template:
    src: sshd_config.j2
    dest: /etc/ssh/sshd_config
    owner: root
    group: root
    mode: '0644'
    backup: yes
    # 在套用前先驗證配置語法
    validate: '/usr/sbin/sshd -t -f %s'
  notify: restart sshd
  tags: ['ssh_config']

- name: 生成更安全的 SSH 主機金鑰
  block:
    - name: 移除弱加密的主機金鑰
      file:
        path: "/etc/ssh/{{ item }}"
        state: absent
      loop:
        - ssh_host_dsa_key
        - ssh_host_dsa_key.pub
        - ssh_host_ecdsa_key
        - ssh_host_ecdsa_key.pub
      notify: restart sshd

    - name: 生成強加密的 RSA 金鑰 (4096 bits)
      command: ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N '' -q
      args:
        creates: /etc/ssh/ssh_host_rsa_key

    - name: 生成 Ed25519 金鑰 (更安全的橢圓曲線)
      command: ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' -q
      args:
        creates: /etc/ssh/ssh_host_ed25519_key

    - name: 設定主機金鑰檔案權限
      file:
        path: "/etc/ssh/{{ item.name }}"
        owner: root
        group: root
        mode: "{{ item.mode }}"
      loop:
        - { name: 'ssh_host_rsa_key', mode: '0600' }
        - { name: 'ssh_host_rsa_key.pub', mode: '0644' }
        - { name: 'ssh_host_ed25519_key', mode: '0600' }
        - { name: 'ssh_host_ed25519_key.pub', mode: '0644' }

- name: 配置 SSH 客戶端安全設定
  template:
    src: ssh_config.j2
    dest: /etc/ssh/ssh_config
    owner: root
    group: root
    mode: '0644'
  tags: ['ssh_client']

- name: 設定 SSH Banner (安全警告)
  template:
    src: ssh_banner.j2
    dest: /etc/ssh/banner
    owner: root
    group: root
    mode: '0644'
  notify: restart sshd
  when: ssh_banner_enabled | default(true)

SSH 配置模板

# roles/security_hardening/templates/sshd_config.j2
# Managed by Ansible – DO NOT EDIT
# CIS Benchmark SSH 安全配置

# 基本設定
Port {{ ssh_port }}
Protocol 2
ListenAddress 0.0.0.0

# 主機金鑰 (只使用強加密演算法)
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ed25519_key

# 加密和演算法設定 (移除弱加密)
KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512

# 認證設定
LoginGraceTime 30
PermitRootLogin {{ 'yes' if ssh_permit_root_login else 'no' }}
StrictModes yes
MaxAuthTries {{ ssh_max_auth_tries }}
MaxSessions 10
MaxStartups 10:30:100

# 密碼和金鑰認證
PasswordAuthentication {{ 'yes' if ssh_password_authentication else 'no' }}
PermitEmptyPasswords no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys

# 連線保持設定 (防止殭屍連線)
ClientAliveInterval {{ ssh_client_alive_interval }}
ClientAliveCountMax {{ ssh_client_alive_count_max }}
TCPKeepAlive yes

# 安全功能
UsePrivilegeSeparation yes
Compression delayed
UseDNS no
PermitUserEnvironment no
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PrintMotd no

# 登入限制
{% if ssh_allowed_users is defined %}
AllowUsers {{ ssh_allowed_users | join(' ') }}
{% endif %}
{% if ssh_allowed_groups is defined %}
AllowGroups {{ ssh_allowed_groups | join(' ') }}
{% endif %}
{% if ssh_denied_users is defined %}
DenyUsers {{ ssh_denied_users | join(' ') }}
{% endif %}

# Banner 和日誌
{% if ssh_banner_enabled | default(true) %}
Banner /etc/ssh/banner
{% endif %}
SyslogFacility AUTHPRIV
LogLevel VERBOSE

# Subsystem
Subsystem sftp /usr/lib/openssh/sftp-server -f AUTHPRIV -l INFO

防火牆安全配置

---
# roles/security_hardening/tasks/firewall.yml

- name: 安裝防火牆管理工具
  package:
    name: "{{ firewall_packages[ansible_os_family] | default(['ufw']) }}"
    state: present

- name: UFW 防火牆配置 (Ubuntu/Debian)
  block:
    - name: 重置 UFW 防火牆規則
      ufw:
        state: reset
      when: firewall_reset | default(false)

    - name: 設定 UFW 預設政策
      ufw:
        direction: "{{ item.direction }}"
        policy: "{{ item.policy }}"
      loop:
        - { direction: 'incoming', policy: 'deny' }
        - { direction: 'outgoing', policy: 'allow' }
        - { direction: 'routed', policy: 'deny' }

    - name: 允許必要的服務端口
      ufw:
        rule: allow
        port: "{{ item.split('/')[0] }}"
        proto: "{{ item.split('/')[1] }}"
        comment: "Ansible managed - {{ item }}"
      loop: "{{ firewall_allowed_ports }}"

    - name: 設定速率限制 (防 DDoS)
      ufw:
        rule: limit
        port: "{{ ssh_port }}"
        proto: tcp
        comment: "SSH brute force protection"

    - name: 允許內部網路通訊
      ufw:
        rule: allow
        src: "{{ item }}"
        comment: "Internal network"
      loop: "{{ firewall_internal_networks | default([]) }}"
      when: firewall_internal_networks is defined

    - name: 啟用 UFW 防火牆
      ufw:
        state: enabled
        logging: "{{ firewall_logging | default('on') }}"

  when: ansible_os_family == "Debian" and firewall_enabled | bool

- name: 設定防火牆日誌輪轉
  template:
    src: firewall_logrotate.j2
    dest: /etc/logrotate.d/ufw
    owner: root
    group: root
    mode: '0644'
  when: firewall_enabled | bool

核心安全參數調整

---
# roles/security_hardening/tasks/kernel_hardening.yml
- name: 套用核心安全參數
  sysctl:
    name: "{{ item.name }}"
    value: "{{ item.value }}"
    state: present
    sysctl_file: /etc/sysctl.d/99-security-hardening.conf
    reload: yes
  loop: "{{ kernel_parameters }}"
  tags: ['sysctl']

- name: 設定額外的安全參數 (CIS Level 2)
  sysctl:
    name: "{{ item.name }}"
    value: "{{ item.value }}"
    state: present
    sysctl_file: /etc/sysctl.d/99-security-hardening.conf
    reload: yes
  loop:
    # ASLR (Address Space Layout Randomization)
    - name: "kernel.randomize_va_space"
      value: "2"
    # Core dump 限制
    - name: "fs.suid_dumpable"
      value: "0"
    # IPv6 停用 (如果不使用的話)
    - name: "net.ipv6.conf.all.disable_ipv6"
      value: "{{ '1' if disable_ipv6 | default(false) else '0' }}"
    # TCP SYN cookies 防護
    - name: "net.ipv4.tcp_syncookies"
      value: "1"
    # ICMP 重導向防護
    - name: "net.ipv4.conf.all.accept_source_route"
      value: "0"
    - name: "net.ipv4.conf.default.accept_source_route"
      value: "0"
    # TCP 時間戳
    - name: "net.ipv4.tcp_timestamps"
      value: "0"
  when: cis_level | string == "2"
  tags: ['sysctl', 'cis_level2']

- name: 設定 limits.conf 安全限制
  template:
    src: security_limits.conf.j2
    dest: /etc/security/limits.d/99-security-hardening.conf
    owner: root
    group: root
    mode: '0644'
  tags: ['limits']

- name: 停用不必要的網路協定
  template:
    src: blacklist_modules.conf.j2
    dest: /etc/modprobe.d/blacklist-security.conf
    owner: root
    group: root
    mode: '0644'
  notify: update initramfs
  tags: ['modules']

日誌和監控配置

---
# roles/security_hardening/tasks/logging_monitoring.yml

- name: 配置 rsyslog 安全日誌
  template:
    src: rsyslog_security.conf.j2
    dest: /etc/rsyslog.d/99-security-hardening.conf
    owner: root
    group: root
    mode: '0644'
  notify: restart rsyslog
  tags: ['rsyslog']

- name: 設定日誌檔案權限
  file:
    path: "{{ item.path }}"
    owner: "{{ item.owner | default('root') }}"
    group: "{{ item.group | default('adm') }}"
    mode: "{{ item.mode }}"
  loop:
    - { path: '/var/log/auth.log', mode: '0640' }
    - { path: '/var/log/syslog', mode: '0640' }
    - { path: '/var/log/kern.log', mode: '0640' }
    - { path: '/var/log/messages', mode: '0640' }
  ignore_errors: yes  # 某些檔案可能不存在
  tags: ['log_permissions']

- name: 安裝和配置 Fail2Ban
  block:
    - name: 安裝 Fail2Ban
      package:
        name: fail2ban
        state: present

    - name: 配置 Fail2Ban jail
      template:
        src: jail.local.j2
        dest: /etc/fail2ban/jail.local
        owner: root
        group: root
        mode: '0644'
      notify: restart fail2ban

    - name: 建立自定義 Fail2Ban filter
      template:
        src: "{{ item }}.conf.j2"
        dest: "/etc/fail2ban/filter.d/{{ item }}.conf"
        owner: root
        group: root
        mode: '0644'
      loop:
        - nginx-limit-req
        - apache-auth
        - custom-ssh
      notify: restart fail2ban

    - name: 啟用 Fail2Ban 服務
      systemd:
        name: fail2ban
        state: started
        enabled: yes

  when: fail2ban_enabled | bool
  tags: ['fail2ban']

- name: 配置 auditd 系統審計
  block:
    - name: 安裝 auditd
      package:
        name: "{{ audit_packages[ansible_os_family] | default(['auditd']) }}"
        state: present

    - name: 配置 audit 規則
      template:
        src: audit.rules.j2
        dest: /etc/audit/rules.d/99-security-hardening.rules
        owner: root
        group: root
        mode: '0640'
      notify: restart auditd

    - name: 配置 auditd.conf
      template:
        src: auditd.conf.j2
        dest: /etc/audit/auditd.conf
        owner: root
        group: root
        mode: '0640'
      notify: restart auditd

    - name: 啟用 auditd 服務
      systemd:
        name: auditd
        state: started
        enabled: yes

  when: audit_enabled | bool
  tags: ['audit']

Fail2Ban 配置模板

# roles/security_hardening/templates/jail.local.j2
# Managed by Ansible – DO NOT EDIT
[DEFAULT]
# 預設設定
bantime = {{ fail2ban_bantime | default('3600') }}
findtime = {{ fail2ban_findtime | default('600') }}
maxretry = {{ fail2ban_maxretry | default('5') }}
backend = auto
usedns = warn

# 通知設定 (可選)
{% if fail2ban_email is defined %}
destemail = {{ fail2ban_email }}
sendername = Fail2Ban-{{ inventory_hostname }}
mta = sendmail
action = %(action_mwl)s
{% else %}
action = %(action_)s
{% endif %}

[sshd]
enabled = true
port = {{ ssh_port }}
logpath = /var/log/auth.log
maxretry = 3
bantime = 7200
findtime = 300

[nginx-http-auth]
enabled = {{ 'true' if 'nginx' in group_names else 'false' }}
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 3

[nginx-noscript]
enabled = {{ 'true' if 'nginx' in group_names else 'false' }}
filter = nginx-noscript
logpath = /var/log/nginx/access.log
maxretry = 6

[nginx-badbots]
enabled = {{ 'true' if 'nginx' in group_names else 'false' }}
filter = apache-badbots
logpath = /var/log/nginx/access.log
maxretry = 2

[nginx-noproxy]
enabled = {{ 'true' if 'nginx' in group_names else 'false' }}
filter = nginx-noproxy
logpath = /var/log/nginx/access.log
maxretry = 2

# 自定義過濾器
[custom-ssh]
enabled = true
filter = custom-ssh
logpath = /var/log/auth.log
maxretry = 2
bantime = 86400  # 24 小時

合規檢查自動化

---
# roles/security_hardening/tasks/compliance_check.yml

- name: 建立合規檢查目錄
  file:
    path: "{{ item }}"
    state: directory
    owner: root
    group: root
    mode: '0750'
  loop:
    - /var/log/compliance
    - /opt/security-scripts
  tags: ['setup']

- name: 部署 CIS Benchmark 檢查腳本
  template:
    src: cis_check.sh.j2
    dest: /opt/security-scripts/cis_check.sh
    owner: root
    group: root
    mode: '0750'
  tags: ['scripts']

- name: 執行 CIS Benchmark 檢查
  command: /opt/security-scripts/cis_check.sh
  register: cis_check_result
  changed_when: false
  failed_when: false
  tags: ['cis_check']

- name: 生成合規報告
  template:
    src: compliance_report.html.j2
    dest: "/var/log/compliance/compliance_report_{{ ansible_date_time.date }}.html"
    owner: root
    group: root
    mode: '0644'
  vars:
    check_timestamp: "{{ ansible_date_time.iso8601 }}"
    cis_results: "{{ cis_check_result.stdout_lines | default([]) }}"
  tags: ['report']

- name: 檢查關鍵安全項目
  block:
    # 檢查是否有弱密碼用戶
    - name: 檢查系統用戶密碼政策
      shell: |
        awk -F: '($2 != "x" && $2 != "*" && $2 != "!") { print $1 }' /etc/passwd
      register: weak_password_users
      changed_when: false

    # 檢查 SUID/SGID 檔案
    - name: 查找系統中的 SUID/SGID 檔案
      shell: |
        find /usr -xdev -type f \( -perm -4000 -o -perm -2000 \) 2>/dev/null
      register: suid_files
      changed_when: false

    # 檢查監聽端口
    - name: 檢查系統監聽端口
      shell: |
        ss -tulpn | grep LISTEN
      register: listening_ports
      changed_when: false

    # 檢查失敗的登入嘗試
    - name: 檢查最近的失敗登入
      shell: |
        lastb -n 20 | head -n -2 || echo "No failed logins"
      register: failed_logins
      changed_when: false

  tags: ['security_audit']

- name: 記錄安全檢查結果
  lineinfile:
    path: /var/log/compliance/security_audit.log
    line: |
      {{ ansible_date_time.iso8601 }} - {{ inventory_hostname }}
      弱密碼用戶: {{ weak_password_users.stdout_lines | length }}
      SUID 檔案數量: {{ suid_files.stdout_lines | length }}
      監聽端口數量: {{ listening_ports.stdout_lines | length }}
      最近失敗登入: {{ failed_logins.stdout_lines | length }}
    create: yes
  tags: ['logging']

- name: 發送安全報告 (可選)
  mail:
    to: "{{ security_report_email | default('admin@company.com') }}"
    subject: "安全合規檢查報告 - {{ inventory_hostname }}"
    body: |
      主機: {{ inventory_hostname }}
      檢查時間: {{ ansible_date_time.iso8601 }}

      檢查結果摘要:
      - 弱密碼用戶: {{ weak_password_users.stdout_lines | length }} 個
      - SUID 檔案: {{ suid_files.stdout_lines | length }} 個
      - 監聽端口: {{ listening_ports.stdout_lines | length }} 個
      - 失敗登入嘗試: {{ failed_logins.stdout_lines | length }} 次

      詳細報告請查看附件。
    attach: "/var/log/compliance/compliance_report_{{ ansible_date_time.date }}.html"
  delegate_to: localhost
  when: security_report_email is defined and send_email_reports | default(false)
  tags: ['notification']

Handlers 定義

---
# roles/security_hardening/handlers/main.yml

- name: restart sshd
  systemd:
    name: sshd
    state: restarted
  listen: restart sshd

- name: restart rsyslog
  systemd:
    name: rsyslog
    state: restarted
  listen: restart rsyslog

- name: restart fail2ban
  systemd:
    name: fail2ban
    state: restarted
  listen: restart fail2ban

- name: restart auditd
  systemd:
    name: auditd
    state: restarted
  listen: restart auditd

- name: update initramfs
  command: update-initramfs -u
  listen: update initramfs

實戰部署 Playbook

主要安全強化 Playbook

---
# security-hardening.yml
- name: 系統安全強化部署
  hosts: all
  become: yes
  vars:
    # 可以在這裡覆寫 role 的預設值
    ssh_port: 2222
    firewall_allowed_ports:
      - "2222/tcp"  # 自定義 SSH 端口
      - "80/tcp"
      - "443/tcp"
      - "8080/tcp"  # 應用程式端口

  pre_tasks:
    - name: 檢查執行權限
      assert:
        that:
          - ansible_user_id != "root" or allow_root_execution | default(false)
        fail_msg: "不建議用 root 執行此 Playbook,請使用有 sudo 權限的一般用戶"

    - name: 確認系統支援性
      assert:
        that:
          - ansible_distribution in ['Ubuntu', 'Debian', 'CentOS', 'RedHat']
          - ansible_distribution_major_version | int >= 18
        fail_msg: "不支援的作業系統或版本太舊"

    - name: 建立執行日誌
      lineinfile:
        path: /var/log/security-hardening.log
        line: "{{ ansible_date_time.iso8601 }} - 開始安全強化 by {{ ansible_user }}"
        create: yes
      delegate_to: localhost

  roles:
    - security_hardening

  post_tasks:
    - name: 執行最終安全檢查
      include_role:
        name: security_hardening
        tasks_from: compliance_check.yml

    - name: 顯示重要安全資訊
      debug:
        msg:
          - "=== 安全強化完成 ==="
          - "SSH 端口已變更為: {{ ssh_port }}"
          - "請確認能夠透過新端口連線後再中斷目前連線"
          - "防火牆已啟用,允許端口: {{ firewall_allowed_ports | join(', ') }}"
          - "Fail2Ban 已啟用,保護關鍵服務"
          - "系統審計已啟用,請定期檢查 /var/log/audit/"
          - "合規報告位於: /var/log/compliance/"

    - name: 最終提醒
      pause:
        prompt: |
          安全強化已完成!請注意:
          1. SSH 端口已改為 {{ ssh_port }},請確認防火牆允許此端口
          2. 強烈建議重新啟動系統以確保所有設定生效
          3. 請保留備份的配置檔案以備不時之需

          是否要立即重新啟動系統?(yes/no)
      register: reboot_confirmation
      when: prompt_for_reboot | default(true)

    - name: 重新啟動系統
      reboot:
        msg: "系統安全強化後重新啟動"
        reboot_timeout: 300
      when:
        - reboot_confirmation is defined
        - reboot_confirmation.user_input | lower in ['yes', 'y']

分環境的安全策略

# group_vars/production.yml
---
cis_level: "2"                    # 生產環境使用更嚴格的安全標準
ssh_port: 2222                    # 非標準端口
ssh_permit_root_login: false      # 禁止 root 登入
firewall_logging: "full"          # 完整防火牆日誌
audit_enabled: true               # 啟用系統審計
fail2ban_enabled: true            # 啟用入侵防護
send_email_reports: true          # 發送安全報告
security_report_email: "security@company.com"

# 生產環境額外的監控
additional_monitoring:
  - ossec
  - tripwire
  - rkhunter
# group_vars/development.yml
---
cis_level: "1"                    # 開發環境使用基本安全標準
ssh_permit_root_login: true       # 允許 root (僅開發環境)
firewall_logging: "low"           # 減少日誌量
audit_enabled: false              # 開發環境不啟用審計
send_email_reports: false         # 不發送報告

# 開發環境可能需要的額外端口
firewall_allowed_ports:
  - "22/tcp"
  - "80/tcp"
  - "443/tcp"
  - "3000/tcp"   # React dev server
  - "8000/tcp"   # Django dev server
  - "5432/tcp"   # PostgreSQL

安全監控 Dashboard

建立安全指標收集

---
# security-monitoring.yml
- name: 部署安全監控
  hosts: monitoring
  become: yes
  tasks:
    - name: 建立安全指標收集腳本
      template:
        src: security_metrics.sh.j2
        dest: /opt/monitoring/security_metrics.sh
        owner: root
        group: root
        mode: '0755'

    - name: 設定定時執行安全檢查
      cron:
        name: "Security metrics collection"
        minute: "*/15"
        job: "/opt/monitoring/security_metrics.sh"
        user: root

    - name: 設定每日安全報告
      cron:
        name: "Daily security report"
        minute: "0"
        hour: "8"
        job: "/opt/security-scripts/daily_security_report.sh"
        user: root

    - name: 建立安全事件告警規則
      template:
        src: security_alerts.yml.j2
        dest: /etc/prometheus/rules/security_alerts.yml
        owner: prometheus
        group: prometheus
        mode: '0644'
      notify: reload prometheus
      when: prometheus_enabled | default(false)

作業練習時間

練習一:基礎安全強化

  1. 在測試環境部署完整的安全強化 Role
  2. 驗證 SSH 安全配置是否生效(嘗試暴力破解測試)
  3. 檢查防火牆規則和 Fail2Ban 狀態
  4. 執行 CIS Benchmark 檢查並查看報告

練習二:客製化安全政策

  1. 根據你的應用需求調整防火牆端口
  2. 設計適合你環境的 auditd 規則
  3. 客製化 Fail2Ban jail 設定
  4. 建立專屬的安全檢查腳本

練習三:合規自動化

  1. 實作自動化的 CIS Level 1 檢查
  2. 設定定期安全掃描和報告生成
  3. 整合安全指標到監控系統
  4. 建立安全事件的告警機制

練習四:安全事件響應

  1. 模擬安全事件(如異常登入)
  2. 測試 Fail2Ban 的自動封鎖功能
  3. 驗證審計日誌的完整性
  4. 練習從安全日誌中分析異常行為

閒話家常

經過今天的學習,相信大家對自動化安全管理有了全面的認識,筆者想分享幾個重要心得:

1. 分層防禦策略

  • 網路層:防火牆、IDS/IPS、DDoS 防護
  • 系統層:權限管控、服務加固、核心參數
  • 應用層:安全配置、輸入驗證、會話管理
  • 資料層:加密、備份、存取控制

2. 安全配置原則

  • 最小權限原則:切記,只給必要權限,絕對不給不必要的權限,但還是要根據現實面考量
  • 預設拒絕原則:沒明確允許的都拒絕
  • 深度防禦原則:多層保護,不依賴單一防線
  • 持續監控原則:安全不是一次性的,需要持續監控

3. 實務建議

  • 測試先行:所有安全設定都要在測試環境驗證
  • 備份重要:變更前必須備份原始配置
  • 文件化:記錄所有安全設定的原因和過程
  • 定期更新:安全威脅在演進,防護手段也要跟上

4. 合規管理心法

  • 自動化優先:人工檢查容易遺漏,自動化更可靠
  • 證據保全:所有檢查結果都要有完整的記錄
  • 持續改進:根據檢查結果不斷優化安全配置
  • 風險評估:了解每項安全設定的風險和成本

記住,安全不是目的,而是手段。我們的目標是在保障安全的前提下,讓系統穩定高效地運行。過度的安全限制可能會影響業務,適度的安全配置才是最好的選擇。

明日預告

明天我們將學習效能監控與擴展,了解如何監控系統效能並實作自動擴展機制!


上一篇
Day26 - Ansible 的除錯與維運
下一篇
Day28 - Ansible 技巧與最佳實務分享
系列文
不爆肝學習 Ansible 的短暫30天30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言