OpenScap OS Benchmark Evaluation

Azure

OpenScap

https://www.open-scap.org/tools/scap-workbench/

https://github.com/OpenSCAP/scap-workbench

# Install
[root@rhel9 scap-workbench-1.2.1]# subscription-manager repos \
--enable=codeready-builder-for-rhel-9-x86_64-rpms \
&& dnf install scap-security-guide openscap-scanner -y
[root@rhel9 scap-workbench-1.2.1]# oscap --help
 
# Initial scan without fixing
sudo oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_cis \
  --results scan-xccdf-results.xml \
  --report scan-xccdf-results.html \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml
    
# Initial scan with fixing the failed items
sudo oscap xccdf eval   \
  --remediate   \ # Be careful with this
  --profile xccdf_org.ssgproject.content_profile_cis   \
  --results scan-xccdf-results.xml   \
  --report scan-xccdf-results.html   \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml  # based on system(pkg scap-security-guide provide)

# Initial scan with fixing and skip some items
sudo oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_cis \
  --results scan-xccdf-results.xml \
  --report scan-xccdf-results.html \
  --remediate \
  --skip-rule xccdf_org.ssgproject.content_rule_partition_for_var_log \
  --skip-rule xccdf_org.ssgproject.content_rule_accounts_umask_etc_bashrc \
  --skip-rule xccdf_org.ssgproject.content_rule_accounts_umask_etc_login_defs \
  --skip-rule xccdf_org.ssgproject.content_rule_accounts_umask_etc_profile \
  --skip-rule xccdf_org.ssgproject.content_rule_service_firewalld_enabled \
  --skip-rule xccdf_org.ssgproject.content_rule_firewalld_loopback_traffic_restricted \
  --skip-rule xccdf_org.ssgproject.content_rule_firewalld_loopback_traffic_trusted \
  --skip-rule xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_ip_forward \
  --skip-rule xccdf_org.ssgproject.content_rule_selinux_not_disabled \
  --skip-rule xccdf_org.ssgproject.content_rule_selinux_state \
  --skip-rule xccdf_org.ssgproject.content_rule_sshd_set_keepalive \
  --skip-rule xccdf_org.ssgproject.content_rule_sshd_limit_user_access \
  --skip-rule xccdf_org.ssgproject.content_rule_sshd_set_max_sessions \
  --skip-rule xccdf_org.ssgproject.content_rule_audit_rules_privileged_commands \
  --skip-rule xccdf_org.ssgproject.content_rule_auditd_data_disk_full_action \
  --skip-rule xccdf_org.ssgproject.content_rule_auditd_data_retention_admin_space_left_action \
  --skip-rule xccdf_org.ssgproject.content_rule_auditd_data_retention_max_log_file_action \
  --skip-rule xccdf_org.ssgproject.content_rule_auditd_data_retention_space_left_action \
  --skip-rule xccdf_org.ssgproject.content_rule_sudo_require_authentication \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml
  
# Initial scan with fixing and skip some items
sudo oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_cis \
  --results scan-xccdf-results.xml \
  --report scan-xccdf-results.html \
  --remediate \
  --skip-rule xccdf_org.ssgproject.content_rule_sudo_require_authentication \
  --skip-rule xccdf_org.ssgproject.content_rule_service_firewalld_enabled \
  --skip-rule xccdf_org.ssgproject.content_rule_selinux_not_disabled \
  --skip-rule xccdf_org.ssgproject.content_rule_selinux_state \
  --skip-rule xccdf_org.ssgproject.content_rule_auditd_data_disk_full_action \
  --skip-rule xccdf_org.ssgproject.content_rule_auditd_data_retention_admin_space_left_action \
  --skip-rule xccdf_org.ssgproject.content_rule_auditd_data_retention_max_log_file_action \
  --skip-rule xccdf_org.ssgproject.content_rule_auditd_data_retention_space_left_action \
  --skip-rule xccdf_org.ssgproject.content_rule_firewalld_loopback_traffic_restricted \
  --skip-rule xccdf_org.ssgproject.content_rule_firewalld_loopback_traffic_trusted \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

# Scan multiple servers with ansible
[work@az-dxb-nl-rh-uat-jump01 ~]$ vim openscan.yml
[work@az-dxb-nl-rh-uat-jump01 ~]$ cat openscan.yml
---
- name: Run OpenSCAP scan on all servers and save reports on control node
  hosts: all
  become: true
  become_user: root
  remote_user: work

  vars:
    report_dir: /tmp
    local_report_dir: "/home/work/openscap_reports"
    scap_datastream: "/usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml"
    scap_profile: "xccdf_org.ssgproject.content_profile_cis"
    skip_rules:
      - xccdf_org.ssgproject.content_rule_partition_for_var_log
      - xccdf_org.ssgproject.content_rule_accounts_umask_etc_bashrc
      - xccdf_org.ssgproject.content_rule_accounts_umask_etc_login_defs
      - xccdf_org.ssgproject.content_rule_accounts_umask_etc_profile
      - xccdf_org.ssgproject.content_rule_service_firewalld_enabled
      - xccdf_org.ssgproject.content_rule_firewalld_loopback_traffic_restricted
      - xccdf_org.ssgproject.content_rule_firewalld_loopback_traffic_trusted
      - xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_ip_forward
      - xccdf_org.ssgproject.content_rule_selinux_not_disabled
      - xccdf_org.ssgproject.content_rule_selinux_state
      - xccdf_org.ssgproject.content_rule_sshd_set_keepalive
      - xccdf_org.ssgproject.content_rule_sshd_limit_user_access
      - xccdf_org.ssgproject.content_rule_sshd_set_max_sessions
      - xccdf_org.ssgproject.content_rule_audit_rules_privileged_commands
      - xccdf_org.ssgproject.content_rule_auditd_data_disk_full_action
      - xccdf_org.ssgproject.content_rule_auditd_data_retention_admin_space_left_action
      - xccdf_org.ssgproject.content_rule_auditd_data_retention_max_log_file_action
      - xccdf_org.ssgproject.content_rule_sudo_require_authentication
      - xccdf_org.ssgproject.content_rule_auditd_data_retention_space_left_action

  tasks:
    - name: Gather installed package facts
      ansible.builtin.package_facts:
        manager: auto

    - name: Ensure openscap-scanner is installed
      ansible.builtin.package:
        name: openscap-scanner
        state: present
      when: "'openscap-scanner' not in ansible_facts.packages"

    - name: Ensure scap-security-guide is installed
      ansible.builtin.package:
        name: scap-security-guide
        state: present
      when: "'scap-security-guide' not in ansible_facts.packages"

    - name: Clean previous OpenSCAP reports from remote /tmp
      ansible.builtin.file:
        path: "{{ item }}"
        state: absent
      loop:
        - "{{ report_dir }}/scan-xccdf-results.html"
        - "{{ report_dir }}/scan-xccdf-results.xml"

    - name: Build OpenSCAP command dynamically
      ansible.builtin.set_fact:
        openscap_command: >-
          oscap xccdf eval
          --remediate
          --profile {{ scap_profile }}
          {% for rule in skip_rules %}
          --skip-rule {{ rule }}
          {% endfor %}
          --report {{ report_dir }}/scan-xccdf-results.html
          --results {{ report_dir }}/scan-xccdf-results.xml
          {{ scap_datastream }}

    - name: Run OpenSCAP scan with skip rules
      ansible.builtin.command: "{{ openscap_command }}"
      args:
        creates: "{{ report_dir }}/scan-xccdf-results.html"
      register: scan_output
      failed_when: scan_output.rc not in [0, 2]

    - name: Ensure local report directory exists on control node
      delegate_to: localhost
      become: false
      ansible.builtin.file:
        path: "{{ local_report_dir }}"
        state: directory
        mode: '0755'

    - name: Fetch HTML report to control node
      become: false
      ansible.builtin.fetch:
        src: "{{ report_dir }}/scan-xccdf-results.html"
        dest: "{{ local_report_dir }}/{{ inventory_hostname }}-report.html"
        flat: yes

    - name: Print OpenSCAP scan summary
      debug:
        var: scan_output.stdout_lines
[work@az-dxb-nl-rh-uat-jump01 ~]$ ansible-playbook openscan.yml
[work@az-dxb-nl-rh-uat-jump01 ~]$ ll ./openscap_reports

image-20250420160159477