From 5783bf4ce443b9771c3b49ac1e4446feb949e1f4 Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Wed, 8 Apr 2026 12:51:49 +0100 Subject: [PATCH 01/10] Workflow updates Signed-off-by: Mark Bolwell --- .../workflows/devel_pipeline_validation.yml | 275 +++++++++--------- .github/workflows/export_badges_private.yml | 6 - .../workflows/main_pipeline_validation.yml | 241 +++++++-------- 3 files changed, 259 insertions(+), 263 deletions(-) diff --git a/.github/workflows/devel_pipeline_validation.yml b/.github/workflows/devel_pipeline_validation.yml index 8fd728a..03b7cc1 100644 --- a/.github/workflows/devel_pipeline_validation.yml +++ b/.github/workflows/devel_pipeline_validation.yml @@ -1,162 +1,163 @@ --- - name: Devel pipeline +name: Devel pipeline - on: # yamllint disable-line rule:truthy - pull_request_target: - types: [opened, reopened, synchronize] - branches: - - devel - - benchmark* - paths: - - '**.yml' - - '**.sh' - - '**.j2' - - '**.ps1' - - '**.cfg' - # Allow manual running of workflow - workflow_dispatch: +on: # yamllint disable-line rule:truthy + pull_request_target: + types: [opened, reopened, synchronize] + branches: + - devel + - benchmark* + paths: + - '**.yml' + - '**.sh' + - '**.j2' + - '**.ps1' + - '**.cfg' + # Allow manual running of workflow + workflow_dispatch: - # A workflow run is made up of one or more jobs - # that can run sequentially or in parallel - jobs: - # This will create messages for first time contributers and direct them to the Discord server - welcome: - runs-on: ubuntu-latest +# A workflow run is made up of one or more jobs +# that can run sequentially or in parallel +jobs: + # This will create messages for first time contributers and direct them to the Discord server + welcome: + runs-on: ubuntu-latest - permissions: - issues: write - pull-requests: write + permissions: + issues: write + pull-requests: write - steps: - - uses: actions/first-interaction@main - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - issue_message: |- - Congrats on opening your first issue and thank you for taking the time to help improve Ansible-Lockdown! - Please join in the conversation happening on the [Discord Server](https://www.lockdownenterprise.com/discord) as well. - pr_message: |- - Congrats on opening your first pull request and thank you for taking the time to help improve Ansible-Lockdown! - Please join in the conversation happening on the [Discord Server](https://www.lockdownenterprise.com/discord) as well. + steps: + - uses: actions/first-interaction@main + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + issue_message: |- + Congrats on opening your first issue and thank you for taking the time to help improve Ansible-Lockdown! + Please join in the conversation happening on the [Discord Server](https://www.lockdownenterprise.com/discord) as well. + pr_message: |- + Congrats on opening your first pull request and thank you for taking the time to help improve Ansible-Lockdown! + Please join in the conversation happening on the [Discord Server](https://www.lockdownenterprise.com/discord) as well. - # This workflow contains a single job that tests the playbook - playbook-test: - # The type of runner that the job will run on - runs-on: self-hosted + # This workflow contains a single job that tests the playbook + playbook-test: + # The type of runner that the job will run on + runs-on: self-hosted - # Allow permissions for AWS auth - permissions: - id-token: write - contents: read - pull-requests: read + # Allow permissions for AWS auth + permissions: + id-token: write + contents: read + pull-requests: read - env: - ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }} - # Imported as a variable by terraform - TF_VAR_repository: ${{ github.event.repository.name }} - AWS_REGION: "us-east-1" - ANSIBLE_VERSION: ${{ vars.ANSIBLE_RUNNER_VERSION }} - defaults: - run: - shell: bash - working-directory: .github/workflows/github_linux_IaC - # working-directory: .github/workflows + env: + ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }} + # Imported as a variable by terraform + TF_VAR_repository: ${{ github.event.repository.name }} + AWS_REGION: "us-east-1" + ANSIBLE_VERSION: ${{ vars.ANSIBLE_RUNNER_VERSION }} + defaults: + run: + shell: bash + working-directory: .github/workflows/github_linux_IaC + # working-directory: .github/workflows - steps: + steps: - - name: Git clone the lockdown repository to test - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} + - name: Git clone the lockdown repository to test + uses: actions/checkout@v6.0.2 + with: + ref: ${{ github.event.pull_request.head.sha }} - - name: If a variable for IAC_BRANCH is set use that branch - working-directory: .github/workflows - run: | - if [ ${{ vars.IAC_BRANCH }} != '' ]; then - echo "IAC_BRANCH=${{ vars.IAC_BRANCH }}" >> $GITHUB_ENV - echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}" - else - echo IAC_BRANCH=main >> $GITHUB_ENV - fi + - name: If a variable for IAC_BRANCH is set use that branch + working-directory: .github/workflows + run: | + if [ ${{ vars.IAC_BRANCH }} != '' ]; then + echo "IAC_BRANCH=${{ vars.IAC_BRANCH }}" >> $GITHUB_ENV + echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}" + else + echo IAC_BRANCH=main >> $GITHUB_ENV + fi - # Pull in terraform code for linux servers - - name: Clone GitHub IaC plan - uses: actions/checkout@v4 - with: - repository: ansible-lockdown/github_linux_IaC - path: .github/workflows/github_linux_IaC - ref: ${{ env.IAC_BRANCH }} + # Pull in terraform code for linux servers + - name: Clone GitHub IaC plan + uses: actions/checkout@v6.0.2 + with: + repository: ansible-lockdown/github_linux_IaC + path: .github/workflows/github_linux_IaC + ref: ${{ env.IAC_BRANCH }} - # Uses dedicated restricted role and policy to enable this only for this task - # No credentials are part of github for AWS auth - - name: configure aws credentials - uses: aws-actions/configure-aws-credentials@main - with: - role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }} - role-session-name: ${{ secrets.AWS_ROLE_SESSION }} - aws-region: ${{ env.AWS_REGION }} + # Uses dedicated restricted role and policy to enable this only for this task + # No credentials are part of github for AWS auth + - name: configure aws credentials + uses: aws-actions/configure-aws-credentials@main + with: + role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }} + role-session-name: ${{ secrets.AWS_ROLE_SESSION }} + aws-region: ${{ env.AWS_REGION }} - - name: DEBUG - Show IaC files - if: env.ENABLE_DEBUG == 'true' - run: | - echo "OSVAR = $OSVAR" - echo "benchmark_type = $benchmark_type" - pwd - env: - # Imported from GitHub variables this is used to load the relevant OS.tfvars file - OSVAR: ${{ vars.OSVAR }} - benchmark_type: ${{ vars.BENCHMARK_TYPE }} + - name: DEBUG - Show IaC files + if: env.ENABLE_DEBUG == 'true' + run: | + echo "OSVAR = $OSVAR" + echo "benchmark_type = $benchmark_type" + pwd + env: + # Imported from GitHub variables this is used to load the relevant OS.tfvars file + OSVAR: ${{ vars.OSVAR }} + benchmark_type: ${{ vars.BENCHMARK_TYPE }} - - name: Tofu init - id: init - run: tofu init - env: - # Imported from GitHub variables this is used to load the relevant OS.tfvars file - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} + - name: Tofu init + id: init + run: tofu init + env: + # Imported from GitHub variables this is used to load the relevant OS.tfvars file + OSVAR: ${{ vars.OSVAR }} + TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - - name: Tofu validate - id: validate - run: tofu validate - env: - # Imported from GitHub variables this is used to load the relevant OS.tfvars file - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} + - name: Tofu validate + id: validate + run: tofu validate + env: + # Imported from GitHub variables this is used to load the relevant OS.tfvars file + OSVAR: ${{ vars.OSVAR }} + TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - - name: Tofu apply - id: apply - env: - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} - TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} - run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false + - name: Tofu apply + id: apply + env: + OSVAR: ${{ vars.OSVAR }} + TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} + TF_VAR_ansible_version: ${{ vars.ANSIBLE_RUNNER_VERSION }} + TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} + TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} + run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false ## Debug Section - - name: DEBUG - Show Ansible hostfile - if: env.ENABLE_DEBUG == 'true' - run: cat hosts.yml + - name: DEBUG - Show Ansible hostfile + if: env.ENABLE_DEBUG == 'true' + run: cat hosts.yml - # Aws deployments taking a while to come up insert sleep or playbook fails +# Aws deployments taking a while to come up insert sleep or playbook fails - - name: Sleep to allow system to come up - run: sleep ${{ vars.BUILD_SLEEPTIME }} + - name: Sleep to allow system to come up + run: sleep ${{ vars.BUILD_SLEEPTIME }} - # Run the Ansible playbook - - name: Run_Ansible_Playbook - env: - ANSIBLE_HOST_KEY_CHECKING: "false" - ANSIBLE_DEPRECATION_WARNINGS: "false" - run: | - /opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml + # Run the Ansible playbook + - name: Run_Ansible_Playbook + env: + ANSIBLE_HOST_KEY_CHECKING: "false" + ANSIBLE_DEPRECATION_WARNINGS: "false" + run: | + /opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml - # Remove test system - User secrets to keep if necessary + # Remove test system - User secrets to keep if necessary - - name: Tofu Destroy - if: always() && env.ENABLE_DEBUG == 'false' - env: - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} - TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} - run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false + - name: Tofu Destroy + if: always() && env.ENABLE_DEBUG == 'false' + env: + OSVAR: ${{ vars.OSVAR }} + TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} + TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} + TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} + run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false diff --git a/.github/workflows/export_badges_private.yml b/.github/workflows/export_badges_private.yml index 761c42e..137bee0 100644 --- a/.github/workflows/export_badges_private.yml +++ b/.github/workflows/export_badges_private.yml @@ -2,12 +2,6 @@ name: Export Private Repo Badges -# Use different minute offsets with the same hourly pattern: -# Repo Group Suggested Cron Expression Explanation -# Group A 0 */6 * * * Starts at top of hour -# Group B 10 */6 * * * Starts at 10 after -# And So On - on: push: branches: diff --git a/.github/workflows/main_pipeline_validation.yml b/.github/workflows/main_pipeline_validation.yml index 6c1d2ea..992e3f3 100644 --- a/.github/workflows/main_pipeline_validation.yml +++ b/.github/workflows/main_pipeline_validation.yml @@ -1,141 +1,142 @@ --- - name: Main pipeline +name: Main pipeline - on: # yamllint disable-line rule:truthy - pull_request_target: - types: [opened, reopened, synchronize] - branches: - - main - - latest - paths: - - '**.yml' - - '**.sh' - - '**.j2' - - '**.ps1' - - '**.cfg' +on: # yamllint disable-line rule:truthy + pull_request_target: + types: [opened, reopened, synchronize] + branches: + - main + - latest + paths: + - '**.yml' + - '**.sh' + - '**.j2' + - '**.ps1' + - '**.cfg' - # Allow permissions for AWS auth - permissions: - id-token: write - contents: read - pull-requests: read +# Allow permissions for AWS auth +permissions: + id-token: write + contents: read + pull-requests: read - # A workflow run is made up of one or more jobs - # that can run sequentially or in parallel - jobs: - # This workflow contains a single job that tests the playbook - playbook-test: - # The type of runner that the job will run on - runs-on: self-hosted - env: - ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }} - # Imported as a variable by terraform - TF_VAR_repository: ${{ github.event.repository.name }} - AWS_REGION : "us-east-1" - ANSIBLE_VERSION: ${{ vars.ANSIBLE_RUNNER_VERSION }} - defaults: - run: - shell: bash - working-directory: .github/workflows/github_linux_IaC - # working-directory: .github/workflows +# A workflow run is made up of one or more jobs +# that can run sequentially or in parallel +jobs: + # This workflow contains a single job that tests the playbook + playbook-test: + # The type of runner that the job will run on + runs-on: self-hosted + env: + ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }} + # Imported as a variable by terraform + TF_VAR_repository: ${{ github.event.repository.name }} + AWS_REGION: "us-east-1" + ANSIBLE_VERSION: ${{ vars.ANSIBLE_RUNNER_VERSION }} + defaults: + run: + shell: bash + working-directory: .github/workflows/github_linux_IaC + # working-directory: .github/workflows - steps: + steps: - - name: Git clone the lockdown repository to test - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} + - name: Git clone the lockdown repository to test + uses: actions/checkout@v6.0.2 + with: + ref: ${{ github.event.pull_request.head.sha }} - - name: If a variable for IAC_BRANCH is set use that branch - working-directory: .github/workflows - run: | - if [ ${{ vars.IAC_BRANCH }} != '' ]; then - echo "IAC_BRANCH=${{ vars.IAC_BRANCH }}" >> $GITHUB_ENV - echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}" - else - echo IAC_BRANCH=main >> $GITHUB_ENV - fi + - name: If a variable for IAC_BRANCH is set use that branch + working-directory: .github/workflows + run: | + if [ ${{ vars.IAC_BRANCH }} != '' ]; then + echo "IAC_BRANCH=${{ vars.IAC_BRANCH }}" >> $GITHUB_ENV + echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}" + else + echo IAC_BRANCH=main >> $GITHUB_ENV + fi - # Pull in terraform code for linux servers - - name: Clone GitHub IaC plan - uses: actions/checkout@v4 - with: - repository: ansible-lockdown/github_linux_IaC - path: .github/workflows/github_linux_IaC - ref: ${{ env.IAC_BRANCH }} + # Pull in terraform code for linux servers + - name: Clone GitHub IaC plan + uses: actions/checkout@v6.0.2 + with: + repository: ansible-lockdown/github_linux_IaC + path: .github/workflows/github_linux_IaC + ref: ${{ env.IAC_BRANCH }} - # Uses dedicated restricted role and policy to enable this only for this task - # No credentials are part of github for AWS auth - - name: configure aws credentials - uses: aws-actions/configure-aws-credentials@main - with: - role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }} - role-session-name: ${{ secrets.AWS_ROLE_SESSION }} - aws-region: ${{ env.AWS_REGION }} + # Uses dedicated restricted role and policy to enable this only for this task + # No credentials are part of github for AWS auth + - name: configure aws credentials + uses: aws-actions/configure-aws-credentials@main + with: + role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }} + role-session-name: ${{ secrets.AWS_ROLE_SESSION }} + aws-region: ${{ env.AWS_REGION }} - - name: DEBUG - Show IaC files - if: env.ENABLE_DEBUG == 'true' - run: | - echo "OSVAR = $OSVAR" - echo "benchmark_type = $benchmark_type" - pwd - ls - env: - # Imported from GitHub variables this is used to load the relevant OS.tfvars file - OSVAR: ${{ vars.OSVAR }} - benchmark_type: ${{ vars.BENCHMARK_TYPE }} + - name: DEBUG - Show IaC files + if: env.ENABLE_DEBUG == 'true' + run: | + echo "OSVAR = $OSVAR" + echo "benchmark_type = $benchmark_type" + pwd + ls + env: + # Imported from GitHub variables this is used to load the relevant OS.tfvars file + OSVAR: ${{ vars.OSVAR }} + benchmark_type: ${{ vars.BENCHMARK_TYPE }} - - name: Tofu init - id: init - run: tofu init - env: - # Imported from GitHub variables this is used to load the relevant OS.tfvars file - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} + - name: Tofu init + id: init + run: tofu init + env: + # Imported from GitHub variables this is used to load the relevant OS.tfvars file + OSVAR: ${{ vars.OSVAR }} + TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - - name: Tofu validate - id: validate - run: tofu validate - env: - # Imported from GitHub variables this is used to load the relevant OS.tfvars file - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} + - name: Tofu validate + id: validate + run: tofu validate + env: + # Imported from GitHub variables this is used to load the relevant OS.tfvars file + OSVAR: ${{ vars.OSVAR }} + TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - - name: Tofu apply - id: apply - env: - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} - TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} - run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false + - name: Tofu apply + id: apply + env: + OSVAR: ${{ vars.OSVAR }} + TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} + TF_VAR_ansible_version: ${{ vars.ANSIBLE_RUNNER_VERSION }} + TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} + TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} + run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false ## Debug Section - - name: DEBUG - Show Ansible hostfile - if: env.ENABLE_DEBUG == 'true' - run: cat hosts.yml + - name: DEBUG - Show Ansible hostfile + if: env.ENABLE_DEBUG == 'true' + run: cat hosts.yml - # Aws deployments taking a while to come up insert sleep or playbook fails +# Aws deployments taking a while to come up insert sleep or playbook fails - - name: Sleep to allow system to come up - run: sleep ${{ vars.BUILD_SLEEPTIME }} + - name: Sleep to allow system to come up + run: sleep ${{ vars.BUILD_SLEEPTIME }} - # Run the Ansible playbook - - name: Run_Ansible_Playbook - env: - ANSIBLE_HOST_KEY_CHECKING: "false" - ANSIBLE_DEPRECATION_WARNINGS: "false" - run: | - /opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml + # Run the Ansible playbook + - name: Run_Ansible_Playbook + env: + ANSIBLE_HOST_KEY_CHECKING: "false" + ANSIBLE_DEPRECATION_WARNINGS: "false" + run: | + /opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml - # Remove test system - User secrets to keep if necessary + # Remove test system - User secrets to keep if necessary - - name: Tofu Destroy - if: always() && env.ENABLE_DEBUG == 'false' - env: - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} - TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} - run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false + - name: Tofu Destroy + if: always() && env.ENABLE_DEBUG == 'false' + env: + OSVAR: ${{ vars.OSVAR }} + TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} + TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} + TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} + run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false From 5dfa35a487b39c573a87c182fb9584b7da5a5f1c Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Wed, 8 Apr 2026 12:52:25 +0100 Subject: [PATCH 02/10] Improved logic for masked steps Signed-off-by: Mark Bolwell --- tasks/section_2/cis_2.1.x.yml | 89 +++++++++++++++++------------------ 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/tasks/section_2/cis_2.1.x.yml b/tasks/section_2/cis_2.1.x.yml index 28e372d..3db8f6d 100644 --- a/tasks/section_2/cis_2.1.x.yml +++ b/tasks/section_2/cis_2.1.x.yml @@ -28,8 +28,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: autofs - enabled: false - state: stopped + enabled: "{{ ('autofs' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('autofs' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true - name: "2.1.2 | PATCH | Ensure avahi daemon services are not in use" @@ -60,8 +60,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: false - state: stopped + enabled: "{{ ('avahi-daemon' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('avahi-daemon' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - avahi-daemon.socket @@ -93,8 +93,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: false - state: stopped + enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - dhcpd.service @@ -126,11 +126,11 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: named.service - enabled: false - state: stopped + enabled: "{{ ('bind' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('bind' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true -- name: "2.1.5 | PATCH | Ensure dnsmasq server services are not in use" +- name: "2.1.5 | PATCH | Ensure dnsmasq services are not in use" when: rhel9cis_rule_2_1_5 tags: - level1-server @@ -141,7 +141,7 @@ - NIST800-53R5_CM-7 - rule_2.1.5 block: - - name: "2.1.5 | PATCH | Ensure dnsmasq server services are not in use | Remove package" + - name: "2.1.5 | PATCH | Ensure dnsmasq services are not in use | Remove package" when: - not rhel9cis_dnsmasq_server - not rhel9cis_dnsmasq_mask @@ -149,15 +149,15 @@ name: dnsmasq state: absent - - name: "2.1.5 | PATCH | Ensure dnsmasq server services are not in use | Mask service" + - name: "2.1.5 | PATCH | Ensure dnsmasq services are not in use | Mask service" when: - not rhel9cis_dnsmasq_server - rhel9cis_dnsmasq_mask notify: Systemd daemon reload ansible.builtin.systemd: name: dnsmasq.service - enabled: false - state: stopped + enabled: "{{ ('dnsmasq' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('dnsmasq' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true - name: "2.1.6 | PATCH | Ensure samba file server services are not in use" @@ -187,8 +187,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: smb.service - enabled: false - state: stopped + enabled: "{{ ('samba' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('samba' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true - name: "2.1.7 | PATCH | Ensure ftp server services are not in use" @@ -218,8 +218,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: vsftpd.service - enabled: false - state: stopped + enabled: "{{ ('vsftpd' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('vsftpd' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true - name: "2.1.8 | PATCH | Ensure message access server services are not in use" @@ -252,8 +252,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: false - state: stopped + enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - "dovecot.socket" @@ -288,8 +288,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: nfs-server.service - enabled: false - state: stopped + enabled: "{{ ('nfs-utils' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('nfs-utils' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true - name: "2.1.10 | PATCH | Ensure nis server services are not in use" @@ -318,8 +318,8 @@ - rhel9cis_nis_mask ansible.builtin.systemd: name: ypserv.service - enabled: false - state: stopped + enabled: "{{ ('ypserv' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('ypserv' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true - name: "2.1.11 | PATCH | Ensure print server services are not in use" @@ -347,8 +347,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: false - state: stopped + enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - "cups.socket" @@ -381,8 +381,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: false - state: stopped + enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - rpcbind.service @@ -415,8 +415,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: false - state: stopped + enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - 'rsyncd.socket' @@ -448,8 +448,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: snmpd.service - enabled: false - state: stopped + enabled: "{{ ('net-snmp' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('net-snmp' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true - name: "2.1.15 | PATCH | Ensure telnet server services are not in use" @@ -479,8 +479,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: telnet.socket - enabled: false - state: stopped + enabled: "{{ ('telnet-server' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('telnet-server' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true - name: "2.1.16 | PATCH | Ensure tftp server services are not in use" @@ -509,8 +509,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: false - state: stopped + enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - 'tftp.socket' @@ -543,8 +543,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: squid.service - enabled: false - state: stopped + enabled: "{{ ('squid' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('squid' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true - name: "2.1.18 | PATCH | Ensure web server services are not in use" @@ -583,8 +583,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: httpd.service - enabled: false - state: stopped + enabled: "{{ ('httpd' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('httpd' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true - name: "2.1.18 | PATCH | Ensure web server services are not in use | Mask nginx service" @@ -594,8 +594,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: ngnix.service - enabled: false - state: stopped + enabled: "{{ ('nginx' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('nginx' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true - name: "2.1.19 | PATCH | Ensure xinetd services are not in use" @@ -624,8 +624,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: xinetd.service - enabled: false - state: stopped + enabled: "{{ ('xinetd' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('xinetd' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true - name: "2.1.20 | PATCH | Ensure X window server services are not in use" @@ -633,8 +633,7 @@ - not rhel9cis_xwindow_server - rhel9cis_rule_2_1_20 tags: - - level1-server - - level1-workstation + - level2-server - automated - patch - xwindow From 2b17f3f1683c9e6b77729eabb02fea7bb67102e1 Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Wed, 8 Apr 2026 12:52:40 +0100 Subject: [PATCH 03/10] updated tags on optional Signed-off-by: Mark Bolwell --- tasks/section_4/cis_4.3.x.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tasks/section_4/cis_4.3.x.yml b/tasks/section_4/cis_4.3.x.yml index 4398df2..21412d3 100644 --- a/tasks/section_4/cis_4.3.x.yml +++ b/tasks/section_4/cis_4.3.x.yml @@ -7,7 +7,11 @@ - rhel9cis_rule_4_3_2 - rhel9cis_rule_4_3_3 - rhel9cis_rule_4_3_4 - tags: always + tags: + - rule_4.3.1 + - rule_4.3.2 + - rule_4.3.3 + - rule_4.3.4 ansible.builtin.command: "nft add table inet {{ rhel9cis_nft_tables_tablename }}" changed_when: true @@ -210,7 +214,7 @@ ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input iif lo accept changed_when: true - - name: "4.3.4 | PATCH | Ensure nftables loopback traffic is configured | Set ip sddr rule | nftables" + - name: "4.3.4 | PATCH | Ensure nftables loopback traffic is configured | Set ip saddr rule | nftables" when: '"ip saddr 127.0.0.0/8 counter packets 0 bytes 0 drop" not in discovered_nftables_ipsaddr.stdout' ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip saddr 127.0.0.0/8 counter drop changed_when: true From dab815f7b6c1b38796942b8f69b8e01fe2257e9a Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Wed, 8 Apr 2026 12:53:02 +0100 Subject: [PATCH 04/10] lin and 7.1.12/13 logic improvements Signed-off-by: Mark Bolwell --- tasks/section_7/cis_7.1.x.yml | 49 +++++++++++++---------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/tasks/section_7/cis_7.1.x.yml b/tasks/section_7/cis_7.1.x.yml index b7655aa..530e72a 100644 --- a/tasks/section_7/cis_7.1.x.yml +++ b/tasks/section_7/cis_7.1.x.yml @@ -1,8 +1,7 @@ --- - name: "7.1.1 | PATCH | Ensure permissions on /etc/passwd are configured" - when: - - rhel9cis_rule_7_1_1 + when: rhel9cis_rule_7_1_1 tags: - level1-server - level1-workstation @@ -18,8 +17,7 @@ mode: 'u-x,go-wx' - name: "7.1.2 | PATCH | Ensure permissions on /etc/passwd- are configured" - when: - - rhel9cis_rule_7_1_2 + when: rhel9cis_rule_7_1_2 tags: - level1-server - level1-workstation @@ -35,8 +33,7 @@ mode: 'u-x,go-wx' - name: "7.1.3 | PATCH | Ensure permissions on /etc/group are configured" - when: - - rhel9cis_rule_7_1_3 + when: rhel9cis_rule_7_1_3 tags: - level1-server - level1-workstation @@ -52,8 +49,7 @@ mode: 'u-x,go-wx' - name: "7.1.4 | PATCH | Ensure permissions on /etc/group- are configured" - when: - - rhel9cis_rule_7_1_4 + when: rhel9cis_rule_7_1_4 tags: - level1-server - level1-workstation @@ -69,8 +65,7 @@ mode: 'u-x,go-wx' - name: "7.1.5 | PATCH | Ensure permissions on /etc/shadow are configured" - when: - - rhel9cis_rule_7_1_5 + when: rhel9cis_rule_7_1_5 tags: - level1-server - level1-workstation @@ -86,8 +81,7 @@ mode: 'ugo-rwx' - name: "7.1.6 | PATCH | Ensure permissions on /etc/shadow- are configured" - when: - - rhel9cis_rule_7_1_6 + when: rhel9cis_rule_7_1_6 tags: - level1-server - level1-workstation @@ -103,8 +97,7 @@ mode: 'ugo-rwx' - name: "7.1.7 | PATCH | Ensure permissions on /etc/gshadow are configured" - when: - - rhel9cis_rule_7_1_7 + when: rhel9cis_rule_7_1_7 tags: - level1-server - level1-workstation @@ -120,8 +113,7 @@ mode: 'ugo-rwx' - name: "7.1.8 | PATCH | Ensure permissions on /etc/gshadow- are configured" - when: - - rhel9cis_rule_7_1_8 + when: rhel9cis_rule_7_1_8 tags: - level1-server - level1-workstation @@ -137,8 +129,7 @@ mode: 'ugo-rwx' - name: "7.1.9 | PATCH | Ensure permissions on /etc/shells are configured" - when: - - rhel9cis_rule_7_1_9 + when: rhel9cis_rule_7_1_9 tags: - level1-server - level1-workstation @@ -154,8 +145,7 @@ mode: 'u-x,go-wx' - name: "7.1.10 | PATCH | Ensure permissions on /etc/security/opasswd are configured" - when: - - rhel9cis_rule_7_1_10 + when: rhel9cis_rule_7_1_10 tags: - level1-server - level1-workstation @@ -173,8 +163,7 @@ register: discovered_file_exists - name: "7.1.11 | PATCH | Ensure world writable files and directories are secured" - when: - - rhel9cis_rule_7_1_11 + when: rhel9cis_rule_7_1_11 tags: - level1-server - level1-workstation @@ -191,7 +180,7 @@ changed_when: false register: discovered_world_writable - - name: "7.1.11 | PATCH | Ensure no world writable files exist | Adjust world-writable files if they exist (Configurable)" + - name: "7.1.11 | PATCH | Ensure world writable files and directories are secured | Adjust world-writable files if they exist (Configurable)" when: - discovered_world_writable.stdout_lines is defined - discovered_world_writable.stdout_lines | length > 0 @@ -202,15 +191,14 @@ state: touch loop: "{{ discovered_world_writable.stdout_lines }}" - - name: "7.1.11 | PATCH | Ensure no world writable files exist | Adjust world-writable directories add sticky bit" + - name: "7.1.11 | PATCH | Ensure world writable files and directories are secured | Adjust world-writable directories add sticky bit" ansible.builtin.shell: df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type d -perm -o+w ! -perm -1002 2>/dev/null | xargs chmod a+t failed_when: discovered_set_stickybit.rc not in [ 0, 123 ] changed_when: discovered_set_stickybit.rc == 0 register: discovered_set_stickybit - name: "7.1.12 | PATCH | Ensure no files or directories without an owner and a group exist" - when: - - rhel9cis_rule_7_1_12 + when: rhel9cis_rule_7_1_12 tags: - level1-server - level1-workstation @@ -223,7 +211,7 @@ warn_control_id: '7.1.12' block: - name: "7.1.12 | AUDIT | Ensure no files or directories without an owner and a group exist | Get list files or directories" - ansible.builtin.command: find {{ rhel9cis_exclude_unowned_search_path }} {{ item.mount }} -xdev \( -nouser -o -nogroup \) -not -fstype nfs + ansible.builtin.command: "find {{ item.mount }} -xdev {{ rhel9cis_exclude_unowned_search_path }} \\( -nouser -o -nogroup \\) -not -fstype nfs" changed_when: false failed_when: false check_mode: false @@ -266,8 +254,7 @@ file: warning_facts.yml - name: "7.1.13 | AUDIT | Ensure SUID and SGID files are reviewed" - when: - - rhel9cis_rule_7_1_13 + when: rhel9cis_rule_7_1_13 tags: - level1-server - level1-workstation @@ -285,7 +272,7 @@ warn_control_id: '7.1.13' block: - name: "7.1.13 | AUDIT | Ensure SUID and SGID files are reviewed | Find SUID and SGID" - ansible.builtin.command: find {{ item.mount }} -xdev -type f -perm \( -02000 or -04000 \) -not -fstype nfs + ansible.builtin.command: find {{ item.mount }} -xdev -type f -perm \( -02000 -o -04000 \) -not -fstype nfs changed_when: false failed_when: false check_mode: false @@ -309,7 +296,7 @@ - "The files are listed below, please confirm the integrity of these binaries" - "{{ discovered_suid_sgid_files_flatten }}" - - name: "7.1.13 | PATCH | Audit SUID executables | Remove SUID bit" + - name: "7.1.13 | PATCH | Ensure SUID and SGID files are reviewed | Remove SUID bit" when: - rhel9cis_suid_sgid_adjust - discovered_suid_sgid_files_flatten | length > 0 From 69bef1f371cca852b2a6aacf3bc0e724aeadcc87 Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Wed, 8 Apr 2026 12:55:50 +0100 Subject: [PATCH 05/10] bootloader updates Signed-off-by: Mark Bolwell --- tasks/section_1/cis_1.4.x.yml | 36 +++++++++++++++++++++++------------ vars/main.yml | 6 ++++-- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/tasks/section_1/cis_1.4.x.yml b/tasks/section_1/cis_1.4.x.yml index 4476d30..7d7c3a6 100644 --- a/tasks/section_1/cis_1.4.x.yml +++ b/tasks/section_1/cis_1.4.x.yml @@ -11,15 +11,27 @@ - patch - rule_1.4.1 - NIST800-53R5_AC-3 - ansible.builtin.copy: - dest: /boot/grub2/user.cfg - content: "GRUB2_PASSWORD={{ rhel9_compiled_bootloader_password }}" # noqa template-instead-of-copy - owner: root - group: root - mode: 'go-rwx' - notify: Grub2cfg + block: + - name: "1.4.1 | PATCH | Ensure bootloader password is set | Set fact if using salt (no python passlib required)" + when: rhel9cis_bootloader_salt | length == 0 + ansible.builtin.set_fact: + rhel9cis_compiled_bootloader_password: "{{ rhel9cis_bootloader_password_hash }}" -- name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured" + - name: "1.4.1 | PATCH | Ensure bootloader password is set | Set fact if using salt (python passlib required)" + when: rhel9cis_bootloader_salt | length > 0 + ansible.builtin.set_fact: + rhel9cis_compiled_bootloader_password: "{{ (rhel9cis_bootloader_password | grub_hash(salt=rhel9cis_bootloader_salt)) }}" # noqa template-instead-of-copy + + - name: "1.4.1 | PATCH | Ensure bootloader password is set" + ansible.builtin.copy: + dest: /boot/grub2/user.cfg + content: "GRUB2_PASSWORD={{ rhel9_compiled_bootloader_password }}" # noqa template-instead-of-copy + owner: root + group: root + mode: 'go-rwx' + notify: Grub2cfg + +- name: "1.4.2 | PATCH | Ensure access to bootloader config is configured" when: rhel9cis_rule_1_4_2 tags: - level1-server @@ -29,7 +41,7 @@ - rule_1.4.2 - NIST800-53R5_AC-3 block: - - name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | bios based system" + - name: "1.4.2 | PATCH | Ensure access to bootloader config is configured | bios based system" when: rhel9cis_legacy_boot ansible.builtin.file: path: "/boot/grub2/{{ item.path }}" @@ -44,7 +56,7 @@ - { path: 'grubenv', mode: 'u-x,go-rwx' } - { path: 'user.cfg', mode: 'u-x,go-rwx' } - - name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | efi based system" + - name: "1.4.2 | PATCH | Ensure access to bootloader config is configured | efi based system" when: not rhel9cis_legacy_boot vars: efi_mount_options: ['umask=0077', 'fmask=0077', 'uid=0', 'gid=0'] @@ -55,13 +67,13 @@ check_mode: false register: discovered_efi_fstab - - name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | efi based system | Build Options" + - name: "1.4.2 | PATCH | Ensure access to bootloader config is configured | efi based system | Build Options" when: item not in discovered_efi_fstab.stdout ansible.builtin.set_fact: efi_mount_opts_addition: "{{ efi_mount_opts_addition + ',' + item }}" loop: "{{ efi_mount_options }}" - - name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | efi based system | Add mount options" + - name: "1.4.2 | PATCH | Ensure access to bootloader config is configured | efi based system | Add mount options" when: efi_mount_opts_addition | length > 0 ansible.builtin.lineinfile: path: /etc/fstab diff --git a/vars/main.yml b/vars/main.yml index 2225042..32a7b18 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -1,6 +1,10 @@ --- + # vars file for RHEL9-CIS +# Set default value for reboot value +change_requires_reboot: false + min_ansible_version: 2.10.1 rhel9cis_allowed_crypto_policies: - 'DEFAULT' @@ -24,8 +28,6 @@ rhel9cis_allowed_crypto_policies_modules: - 'NO-SSHWEAKMAC' - 'NO-WEAKMAC' -rhel9_compiled_bootloader_password: "{% if rhel9cis_bootloader_salt != '' %}{{ (rhel9cis_bootloader_password | grub_hash(salt=rhel9cis_bootloader_salt)) }}{% else %}{{ rhel9cis_bootloader_password_hash }}{% endif %}" # noqa template-instead-of-copy - # Used to control warning summary warn_control_list: "" warn_count: 0 From 201edf02e4c07fc5b5ca00b96bb9f0a45d7e622e Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Wed, 8 Apr 2026 12:56:24 +0100 Subject: [PATCH 06/10] QA, lint, standards, var naming, title aming aligned Signed-off-by: Mark Bolwell --- .gitignore | 23 +- .yamllint | 2 +- CONTRIBUTING.rst | 4 +- Changelog.md | 57 +- defaults/main.yml | 655 +++++++----------- tasks/LE_audit_setup.yml | 2 +- tasks/auditd.yml | 56 +- tasks/main.yml | 8 +- tasks/post_remediation_audit.yml | 10 +- tasks/pre_remediation_audit.yml | 16 +- tasks/prelim.yml | 7 + tasks/section_1/cis_1.1.2.3.x.yml | 6 +- tasks/section_1/cis_1.1.2.4.x.yml | 6 +- tasks/section_1/cis_1.1.2.5.x.yml | 6 +- tasks/section_1/cis_1.1.2.6.x.yml | 6 +- tasks/section_1/cis_1.1.2.7.x.yml | 6 +- tasks/section_1/cis_1.3.1.x.yml | 4 +- tasks/section_1/cis_1.5.x.yml | 6 +- tasks/section_1/cis_1.6.x.yml | 6 +- tasks/section_1/cis_1.7.x.yml | 6 +- tasks/section_1/cis_1.8.x.yml | 4 +- tasks/section_2/cis_2.2.x.yml | 2 +- tasks/section_2/cis_2.4.x.yml | 2 +- tasks/section_3/cis_3.3.x.yml | 68 +- tasks/section_5/cis_5.1.x.yml | 18 +- tasks/section_5/cis_5.3.1.x.yml | 2 +- tasks/section_5/cis_5.3.2.x.yml | 2 +- tasks/section_5/cis_5.3.3.1.x.yml | 4 +- tasks/section_5/cis_5.3.3.2.x.yml | 10 +- tasks/section_5/cis_5.3.3.3.x.yml | 6 +- tasks/section_5/cis_5.3.3.4.x.yml | 4 +- tasks/section_5/cis_5.4.1.x.yml | 12 +- tasks/section_5/cis_5.4.2.x.yml | 4 +- tasks/section_6/cis_6.2.2.x.yml | 2 +- tasks/section_6/cis_6.2.3.x.yml | 24 +- tasks/section_6/cis_6.3.1.x.yml | 6 +- tasks/section_6/cis_6.3.3.x.yml | 24 +- .../rules.d}/98_auditd_exception.rules.j2 | 0 .../audit/rules.d}/99_auditd.rules.j2 | 0 39 files changed, 478 insertions(+), 608 deletions(-) rename templates/{audit => etc/audit/rules.d}/98_auditd_exception.rules.j2 (100%) rename templates/{audit => etc/audit/rules.d}/99_auditd.rules.j2 (100%) diff --git a/.gitignore b/.gitignore index de8046f..65aacd6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ .env *.log *.retry -.cache .vagrant tests/*redhat-subscription tests/Dockerfile @@ -10,11 +9,9 @@ tests/Dockerfile packer_cache delete* ignore* -test_inv -# temp remove doc while this is built up -doc/ # VSCode .vscode +vagrant # Byte-compiled / optimized / DLL files __pycache__/ @@ -39,13 +36,29 @@ tramp rh-creds.env travis.env +# Secret/key files +*.vault +*.key +*.pem +*.p12 +*.pfx +*.keystore +*.jks +*.credentials +*vault_pass* +.vault_pass + # Lockdown-specific benchparse/ *xccdf.xml *.retry +*.pdf +*history.md +*plan.md +*qa_report* # GitHub Action/Workflow files .github/ -# Precommit exclusions +# ansible-lint .ansible/ diff --git a/.yamllint b/.yamllint index af0d9ab..c1b1254 100644 --- a/.yamllint +++ b/.yamllint @@ -17,7 +17,7 @@ rules: comments: ignore-shebangs: true min-spaces-from-content: 1 # prettier compatibility - comments-indentation: enable + comments-indentation: disable empty-lines: max: 1 indentation: diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index d7cdcbf..a2083de 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1,4 +1,4 @@ -Contributing to MindPoint Group Projects +Contributing to Ansible-Lockdown Projects ======================================== Rules @@ -20,7 +20,7 @@ Signing your contribution We've chosen to use the Developer's Certificate of Origin (DCO) method that is employed by the Linux Kernel Project, which provides a simple -way to contribute to MindPoint Group projects. +way to contribute to Ansible-Lockdown projects. The process is to certify the below DCO 1.1 text :: diff --git a/Changelog.md b/Changelog.md index 035d685..1775cce 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,7 +1,34 @@ # Changes to RHEL9CIS -## 2.0.5 - Based on CIS v2.0.0 +## April 2026 + +- bootloader password logic improved thanks to skullbringer on discord community +- 7.1.12 and 7.1.13 fixed thanks to @bubaimondalsch #440 +- 4.3 tags updated +- 2.1.x - improve logic for mask/disable/stop thanks to @numericillustration #434 + +## March 2026 — workspace alignment + +- Common files aligned to std +- workflows updates +- titles updates +- levels aligned +- auditd improvement +- grammar, lint +- vars naming +- Linting: converted ~75 single-item when: conditions from list to inline format +- Linting: added blank line after --- YAML document marker in 10 files +- Linting: fixed register: key order in 8 tasks (now appears after changed_when/failed_when) +- Linting: fixed spelling typo sddr → saddr in cis_4.3.x.yml +- Defaults: added justification comments for service client and bluetooth variables + +## Based on CIS v2.0.0 + +# Feb26 2 +#430 thanks to @numericillustration - 5.4.2.5 missing echo + +# Feb26 1 - QA Fixes - .j2 Branding Update - Added rhel9cis_uses_root variable definition for 5.4.2.5 root PATH integrity task @@ -77,34 +104,6 @@ tidy up tags on tasks/main.yml - public issue 372 - allow password with different locale -## 2.0.4 - Based on CIS v2.0.0 - -- addressed issue #419, thank you @aaronk1 -- addressed issue #418 thank you @bbaassssiiee -- addressed issue #416 thank you @georgenalen and @bbaassssiiee -- addressed issue #393 thank you to @fragglexarmy -- addressed issue #394 thank you to @dbeuker -- addressed issues #390 and #391 thanks to @polski-g -- addressed issue #398 & #399 thanks to trumbaut -- Added max-concurrent options for audit -- work flow updates -- audit logic improvements -- auditd template 2.19 compatible -- pre-commit updates -- #410 thanks to @kpi-nourman -- #413 thanks to @bbaassssiiee - -## 2.0.3 - Based on CIS v2.0.0 -- addressed issue #387, thank you @fragglexarmy -- addressed issue #382 to improve regex logic on 5.4.2.4 -- improvement on crypto policy managed controls with var logic -- addressed issue #384 thank you @polski-g -- update command to shell module on tasks -- addressed issue 371 thanks to @bgro and kodebach -- addressed issue 350 thanks to @chrispipo -- addressed issue 364 thanks to @polski-g -- pre-commit update - ## 2.0.2 - Based on CIS v2.0.0 - Update to audit_only to allow fetching results diff --git a/defaults/main.yml b/defaults/main.yml index 7de968f..6a1ec42 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -13,7 +13,7 @@ os_check: true ## Run tests that are considered higher risk and could have a system impact if not properly tested ## Default false ## Will be fine if clean new un-configured build -rhel9cis_disruption_high: true +rhel9cis_disruption_high: false ## Switching on/off specific baseline sections # These variables govern whether the tasks of a particular section are to be executed when running the role. @@ -42,7 +42,6 @@ rhel9cis_level_2: true # Create managed not custom local_facts files create_benchmark_facts: true -# The path where the ansible facts file is created if audit facts are not present ansible_facts_path: /etc/ansible/facts.d ## Section 1.6 - Mandatory Access Control @@ -75,17 +74,10 @@ change_requires_reboot: false ### Goss is required on the remote host ### ### vars/auditd.yml for other settings ### -## Audit setup -# Audits are carried out using Goss. This variable -# determines whether execution of the role prepares for auditing -# by installing the required binary. +# Allow audit to setup the requirements including installing git (if option chosen and downloading and adding goss binary to system) setup_audit: false -## Enable audits to run - this runs the audit and get the latest content -# This variable governs whether the audit using the -# separately maintained audit role using Goss -# is carried out. -# This runs the audit and gets the latest content +# enable audits to run - this runs the audit and get the latest content run_audit: false # Run heavy tests - some tests can have more impact on a system enabling these can have greater impact on a system audit_run_heavy_tests: true @@ -106,16 +98,8 @@ get_audit_binary_method: download ## e.g copy from ansible control node to remote host audit_bin_copy_location: /some/accessible/path -## How to retrieve the audit role -# The role for auditing is maintained separately. -# This variable specifies the method of how to get the audit role +# how to get audit files onto host options # options are git/copy/archive/get_url other e.g. if you wish to run from already downloaded conf -# onto the system. The options are as follows: -# - 'git': clone audit content from GitHub REPOSITORY, set up via `audit_file_git` var, and -# VERSION(e.g. branch, tag name), set up via `audit_git_version` var. -# - 'copy': copy from path as specified in variable `audit_conf_copy`. -# - 'archive': same as 'copy', only that the specified filepath needs to be unpacked. -# - 'get_url': Download from url as specified in variable `audit_files_url` audit_content: git # If using either archive, copy, get_url: @@ -153,7 +137,6 @@ audit_output_destination: /opt/audit_summaries/ # PLEASE NOTE: These work in coordination with the section # group variables and tags. # You must enable an entire section in order for the variables below to take effect. -## Section 1 Fixes # Section 1 is Initial setup (FileSystem Configuration, Configure Software Updates, Filesystem Integrity Checking, Secure Boot Settings, # Additional Process Hardening, Mandatory Access Control, Command Line Warning Banners, and GNOME Display Manager) # Filesystem kernel modules @@ -200,6 +183,7 @@ rhel9cis_rule_1_1_2_7_1: true rhel9cis_rule_1_1_2_7_2: true rhel9cis_rule_1_1_2_7_3: true rhel9cis_rule_1_1_2_7_4: true + # Package Mgmt # Config Pkg Repos rhel9cis_rule_1_2_1_1: true @@ -208,6 +192,7 @@ rhel9cis_rule_1_2_1_3: true rhel9cis_rule_1_2_1_4: true # Package updates rhel9cis_rule_1_2_2_1: true + # Selinux rhel9cis_rule_1_3_1_1: true rhel9cis_rule_1_3_1_2: true @@ -217,14 +202,17 @@ rhel9cis_rule_1_3_1_5: true rhel9cis_rule_1_3_1_6: true rhel9cis_rule_1_3_1_7: true rhel9cis_rule_1_3_1_8: true + # Bootloader rhel9cis_rule_1_4_1: true rhel9cis_rule_1_4_2: true + # Additional Process Hardening rhel9cis_rule_1_5_1: true rhel9cis_rule_1_5_2: true rhel9cis_rule_1_5_3: true rhel9cis_rule_1_5_4: true + # Config system wide Crypto rhel9cis_rule_1_6_1: true rhel9cis_rule_1_6_2: true @@ -233,6 +221,7 @@ rhel9cis_rule_1_6_4: true rhel9cis_rule_1_6_5: true rhel9cis_rule_1_6_6: true rhel9cis_rule_1_6_7: true + # Command line warning banners rhel9cis_rule_1_7_1: true rhel9cis_rule_1_7_2: true @@ -240,6 +229,7 @@ rhel9cis_rule_1_7_3: true rhel9cis_rule_1_7_4: true rhel9cis_rule_1_7_5: true rhel9cis_rule_1_7_6: true + # Gnome Display Manager rhel9cis_rule_1_8_1: true rhel9cis_rule_1_8_2: true @@ -276,18 +266,21 @@ rhel9cis_rule_2_1_19: true rhel9cis_rule_2_1_20: true rhel9cis_rule_2_1_21: true rhel9cis_rule_2_1_22: true -# Configure Client Services + +## Configure Client Services rhel9cis_rule_2_2_1: true rhel9cis_rule_2_2_2: true rhel9cis_rule_2_2_3: true rhel9cis_rule_2_2_4: true rhel9cis_rule_2_2_5: true -# Configure Time Synchronization + +## Configure Time Synchronization rhel9cis_rule_2_3_1: true rhel9cis_rule_2_3_2: true rhel9cis_rule_2_3_3: true -# Job Schedulers -# cron + +## Job Schedulers +### cron rhel9cis_rule_2_4_1_1: true rhel9cis_rule_2_4_1_2: true rhel9cis_rule_2_4_1_3: true @@ -296,16 +289,15 @@ rhel9cis_rule_2_4_1_5: true rhel9cis_rule_2_4_1_6: true rhel9cis_rule_2_4_1_7: true rhel9cis_rule_2_4_1_8: true -# at +### at rhel9cis_rule_2_4_2_1: true -## Section 3 Fixes -# Section 3 rules are used for securely configuring the network configuration(kernel params, ACL, Firewall settings) -# Network Devices +# Section 3 Network +## Network Devices rhel9cis_rule_3_1_1: true rhel9cis_rule_3_1_2: true rhel9cis_rule_3_1_3: true -# Network Kernel Modules +## Network Kernel Modules rhel9cis_rule_3_2_1: true rhel9cis_rule_3_2_2: true rhel9cis_rule_3_2_3: true @@ -323,13 +315,11 @@ rhel9cis_rule_3_3_9: true rhel9cis_rule_3_3_10: true rhel9cis_rule_3_3_11: true -## Section 4 Fixes -# Section 4 rules are Logging and Auditing (Configure System Accounting (auditd), -# Configure Data Retention, and Configure Logging) -# Firewall utility +# Section 4 Firewalls +## Firewall utility rhel9cis_rule_4_1_1: true rhel9cis_rule_4_1_2: true -# Configure firewalld +## Configure firewalld rhel9cis_rule_4_2_1: true rhel9cis_rule_4_2_2: true # Configure nftables @@ -338,10 +328,8 @@ rhel9cis_rule_4_3_2: true rhel9cis_rule_4_3_3: true rhel9cis_rule_4_3_4: true -## Section 5 Fixes -# Section 5 rules control Access, Authentication, and Authorization (Configure time-based job schedulers, -# Configure sudo, Configure SSH Server, Configure PAM and User Accounts and Environment) -# Configure SSH Server +## Section 5 +## 5.1. Configure SSH Server rhel9cis_rule_5_1_1: true rhel9cis_rule_5_1_2: true rhel9cis_rule_5_1_3: true @@ -364,7 +352,7 @@ rhel9cis_rule_5_1_19: true rhel9cis_rule_5_1_20: true rhel9cis_rule_5_1_21: true rhel9cis_rule_5_1_22: true -# 5.2 Configure Privilege Escalation +## 5.2 Configure Privilege Escalation rhel9cis_rule_5_2_1: true rhel9cis_rule_5_2_2: true rhel9cis_rule_5_2_3: true @@ -426,18 +414,17 @@ rhel9cis_rule_5_4_3_1: true rhel9cis_rule_5_4_3_2: true rhel9cis_rule_5_4_3_3: true -## Section 6 Fixes -# Section 6 rules control Logging and Auditing -# Configure Integrity Checking +# Section 6 Logging and Auditing +## 6.1 Configure Integrity Checking rhel9cis_rule_6_1_1: true rhel9cis_rule_6_1_2: true rhel9cis_rule_6_1_3: true -# 6.2.1 Configure systemd-journald service +## 6.2.1 Configure systemd-journald service rhel9cis_rule_6_2_1_1: true rhel9cis_rule_6_2_1_2: true rhel9cis_rule_6_2_1_3: true rhel9cis_rule_6_2_1_4: true -# 6.2.2.x Configure journald +## 6.2.2.x Configure journald rhel9cis_rule_6_2_2_1_1: true rhel9cis_rule_6_2_2_1_2: true rhel9cis_rule_6_2_2_1_3: true @@ -445,7 +432,7 @@ rhel9cis_rule_6_2_2_1_4: true rhel9cis_rule_6_2_2_2: true rhel9cis_rule_6_2_2_3: true rhel9cis_rule_6_2_2_4: true -# 6.2.3 Configure rsyslog +## 6.2.3 Configure rsyslog rhel9cis_rule_6_2_3_1: true rhel9cis_rule_6_2_3_2: true rhel9cis_rule_6_2_3_3: true @@ -454,20 +441,20 @@ rhel9cis_rule_6_2_3_5: true rhel9cis_rule_6_2_3_6: true rhel9cis_rule_6_2_3_7: true rhel9cis_rule_6_2_3_8: true -# 6.2.4 Configure Logfiles +## 6.2.4 Configure Logfiles rhel9cis_rule_6_2_4_1: true -# 6.3 Configure Auditing -# 6.3.1 Configure auditd Service +## 6.3 Configure Auditing +## 6.3.1 Configure auditd Service rhel9cis_rule_6_3_1_1: true rhel9cis_rule_6_3_1_2: true rhel9cis_rule_6_3_1_3: true rhel9cis_rule_6_3_1_4: true -# 6.3.2 Configure Data Retention +## 6.3.2 Configure Data Retention rhel9cis_rule_6_3_2_1: true rhel9cis_rule_6_3_2_2: true rhel9cis_rule_6_3_2_3: true rhel9cis_rule_6_3_2_4: true -# 6.3.3 Configure auditd Rules +## 6.3.3 Configure auditd Rules rhel9cis_rule_6_3_3_1: true rhel9cis_rule_6_3_3_2: true rhel9cis_rule_6_3_3_3: true @@ -489,7 +476,7 @@ rhel9cis_rule_6_3_3_18: true rhel9cis_rule_6_3_3_19: true rhel9cis_rule_6_3_3_20: true rhel9cis_rule_6_3_3_21: true -# 6.3.4 Configure auditd File Access +## 6.3.4 Configure auditd File Access rhel9cis_rule_6_3_4_1: true rhel9cis_rule_6_3_4_2: true rhel9cis_rule_6_3_4_3: true @@ -501,9 +488,8 @@ rhel9cis_rule_6_3_4_8: true rhel9cis_rule_6_3_4_9: true rhel9cis_rule_6_3_4_10: true -## Section 7 Fixes -# Section 7 rules control System Maintenance -# System File Permissions +# Section 7 System Maintenance +## 7.1 System File Permissions rhel9cis_rule_7_1_1: true rhel9cis_rule_7_1_2: true rhel9cis_rule_7_1_3: true @@ -517,7 +503,7 @@ rhel9cis_rule_7_1_10: true rhel9cis_rule_7_1_11: true rhel9cis_rule_7_1_12: true rhel9cis_rule_7_1_13: true -# 7.2 Local User and Group Settings +## 7.2 Local User and Group Settings rhel9cis_rule_7_2_1: true rhel9cis_rule_7_2_2: true rhel9cis_rule_7_2_3: true @@ -546,12 +532,12 @@ rhel9cis_tmp_svc: false # Setting to `true` will allow a test on the package and force the import of the key rhel9cis_force_gpg_key_import: true -## Control 1.2.1.3 +## Control 1.2.4 # When installing RHEL from authorized Red Hat source, RHEL will come with default YUM repository. NOT having a default YUM # repo ('rhel9cis_rhel_default_repo' set as 'false'), in conjunction with 'rhel9cis_rule_enable_repogpg' set as 'True', will enable the tasks # which check the GPG signatures for all the individual YUM repositories. rhel9cis_rhel_default_repo: true -## Control 1.2.1.3 +## Control 1.2.4 # When 'rhel9cis_rule_enable_repogpg' is set to 'true'(in conjunction with 'rhel9cis_rhel_default_repo':'false'), conditions are met for # enabling the GPG signatures-check for all the individual YUM repositories. If GPG signatures-check is enabled on repositories which do not # support it(like RedHat), installation of packages will fail. @@ -563,7 +549,7 @@ rhel9cis_rule_enable_repogpg: true # and may prevent some services from running. Requires SELinux not being disabled (by # having 'rhel9cis_selinux_disable' var set as 'true'), otherwise setting will be ignored. rhel9cis_selinux_pol: targeted -## Control 1.3.1.3|4|5 - SELinux policy settings +## Control 1.3.1.3|4 - SELinux configured and not disabled # This variable contains a specific SELinux mode, respectively: # - 'enforcing': SELinux policy IS enforced, therefore denies operations based on SELinux policy # rules. If system was installed with SELinux, this is enabled by default. @@ -576,13 +562,16 @@ rhel9cis_selinux_pol: targeted rhel9cis_selinux_enforce: enforcing ## Control 1.4.1 -# This variable governs whether a bootloader password should be set in '/boot/grub2/user.cfg' file. -rhel9cis_set_boot_pass: false -################### bootloader password ############################################################ +################### bootloader password ##################################### # # Two options for setting the bootloader password # +# Will also need to add the set_boot_pass variable to the task to ensure the password is set. +# +# This variable governs whether a bootloader password should be set in '/boot/grub2/user.cfg' file. +rhel9cis_set_boot_pass: false +# # Option 1: Set the bootloader password and salt – requires the passlib Python module # to be available on the Ansible controller. # Set this value to something secure to have predictable hashes, @@ -602,14 +591,14 @@ rhel9cis_bootloader_password: 'password' # pragma: allowlist secret rhel9cis_bootloader_password_hash: 'grub.pbkdf2.sha512.changethispassword' # pragma: allowlist secret -###################################################################################################### +#################################################### ## Controls 1.6.x and Controls 5.1.x # This variable governs if current Ansible role should manage system-wide crypto policy. rhel9cis_crypto_policy_ansiblemanaged: true # This variable contains the value to be set as the system-wide crypto policy. Current rule enforces NOT USING # 'LEGACY' value(as it is less secure, it just ensures compatibility with legacy systems), therefore -# possible values for this variable are, as explained by RedHat docs: +# The variable can have these possible values, as explained by RedHat docs: # -'DEFAULT': reasonable default policy for today's standards (balances usability and security) # -'FUTURE': conservative security level that is believed to withstand any near-term future attacks # -'FIPS': A level that conforms to the FIPS140-2 requirements @@ -631,12 +620,7 @@ rhel9cis_warning_banner: Authorized users only. All activity may be monitored an ## Control 1.8.x - Settings for GDM # do not run Control 1.8.x if using a display manager different than gdm rhel9cis_display_manager: "gdm" -# This variable governs whether rules dealing with GUI specific packages(and/or their settings) should -# be executed either to: -# - secure GDM, if GUI is needed('rhel9cis_gui: true') -# - or remove GDM and X-Windows-system, if no GUI is needed('rhel9cis_gui: false') -# The value of this variable is set automatically, if gnome is present this variable -# will always have `true` as a value, and `false` otherwise. +## 1.8 GDM graphical interface rhel9cis_gui: "{{ prelim_gnome_present.stat.exists | default(false) }}" # This variable specifies the GNOME configuration database file to which configurations are written. # (See "https://help.gnome.org/admin/system-admin-guide/stable/dconf-keyfiles.html.en") @@ -684,147 +668,99 @@ rhel9cis_chrony_server_makestep: "1.0 3" # improve the reliability, because multiple sources will need to correspond with each other. rhel9cis_chrony_server_minsources: 2 -### -### The set of rules that make up section 2.1, are used for ensuring that -### certain services are not installed on the OS. -### The following list of variables contain two types: the ones that end in '_services', and the ones that end in '_mask' -### in '_mask'. For completely removing a service both those variables referencing that service shall be set to 'false'. -### For masking a service the type that ends in '_mask' shall be set to 'true'. -### Set this variable to `true` to keep service `autofs`; otherwise, the service is uninstalled. -### - -########################################### - -## Controls 2.1.x - Configure Server Services -# Set this variable to `true` to keep service `autofs`; otherwise, the service is uninstalled. +# Service configuration +# Options are +# Service +# - false - removes package +# - true - leaves package installed +# Mask +# - false - leaves service in current status +# - true - sets service name to masked +# +# Setting both Service and Mask to false will remove the package if exists rhel9cis_autofs_services: false -# Set this variable to `true` to mask service `autofs`. rhel9cis_autofs_mask: false -# Set this variable to `true` to keep service `avahi`; otherwise, the service is uninstalled. rhel9cis_avahi_server: false -# Set this variable to `true` to mask service `avahi`. rhel9cis_avahi_mask: false -# Set this variable to `true` to keep service `dhcp`; otherwise, the service is uninstalled. rhel9cis_dhcp_server: false -# Set this variable to `true` to mask service `dhcp`. rhel9cis_dhcp_mask: false -# Set this variable to `true` to keep service `dns`; otherwise, the service is uninstalled. rhel9cis_dns_server: false -# Set this variable to `true` to mask service `dns`. rhel9cis_dns_mask: false -# Set this variable to `true` to keep service `dnsmasq`; otherwise, the service is uninstalled. rhel9cis_dnsmasq_server: false -# Set this variable to `true` to mask service `dnsmasq`. rhel9cis_dnsmasq_mask: false -# Set this variable to `true` to keep service `samba`; otherwise, the service is uninstalled. rhel9cis_samba_server: false -# Set this variable to `true` to mask service `samba`. rhel9cis_samba_mask: false -# Set this variable to `true` to keep service `ftp`; otherwise, the service is uninstalled. rhel9cis_ftp_server: false -# Set this variable to `true` to mask service `ftp`. rhel9cis_ftp_mask: false -# Set this variable to `true` to keep service `message`; otherwise, the service is uninstalled. rhel9cis_message_server: false # This is for messaging dovecot and cyrus-imap -# Set this variable to `true` to mask service `message`. rhel9cis_message_mask: false -# Set this variable to `true` to keep service `nfs`; otherwise, the service is uninstalled. rhel9cis_nfs_server: true -# Set this variable to `true` to mask service `nfs`. rhel9cis_nfs_mask: true -# Set this variable to `true` to keep service `nis`; otherwise, the service is uninstalled. rhel9cis_nis_server: true # set to mask if nis client required -# Set this variable to `true` to mask service `nis`. rhel9cis_nis_mask: false -# Set this variable to `true` to keep service `print`; otherwise, the service is uninstalled. rhel9cis_print_server: false # replaces cups -# Set this variable to `true` to mask service `print`. rhel9cis_print_mask: false -# Set this variable to `true` to keep service `rpc`; otherwise, the service is uninstalled. rhel9cis_rpc_server: true -# Set this variable to `true` to mask service `rpc`. rhel9cis_rpc_mask: true -# Set this variable to `true` to keep service `rsync`; otherwise, the service is uninstalled. rhel9cis_rsync_server: false -# Set this variable to `true` to mask service `rsync`. rhel9cis_rsync_mask: false -# Set this variable to `true` to keep service `snmp`; otherwise, the service is uninstalled. rhel9cis_snmp_server: false -# Set this variable to `true` to mask service `snmp`. rhel9cis_snmp_mask: false -# Set this variable to `true` to keep service `telnet`; otherwise, the service is uninstalled. rhel9cis_telnet_server: false -# Set this variable to `true` to mask service `telnet`. rhel9cis_telnet_mask: false -# Set this variable to `true` to keep service `tftp`; otherwise, the service is uninstalled. rhel9cis_tftp_server: false -# Set this variable to `true` to mask service `tftp`. rhel9cis_tftp_mask: false -# Set this variable to `true` to keep service `squid`; otherwise, the service is uninstalled. rhel9cis_squid_server: false -# Set this variable to `true` to mask service `squid`. rhel9cis_squid_mask: false -# Set this variable to `true` to keep service `httpd`; otherwise, the service is uninstalled. rhel9cis_httpd_server: false -# Set this variable to `true` to mask service `httpd`. rhel9cis_httpd_mask: false -# Set this variable to `true` to keep service `nginx`; otherwise, the service is uninstalled. rhel9cis_nginx_server: false -# Set this variable to `true` to mask service `nginx`. rhel9cis_nginx_mask: false -# Set this variable to `true` to keep service `xinetd`; otherwise, the service is uninstalled. rhel9cis_xinetd_server: false -# Set this variable to `true` to mask service `xinetd`. rhel9cis_xinetd_mask: false -# Set this variable to `true` to keep service `xwindow`; otherwise, the service is uninstalled. rhel9cis_xwindow_server: false # will remove mask not an option - -## Control 2.1.21 - Ensure mail transfer agent is configured for local-only mode -# This variable if set to 'false', ensures that the mail transfer agent is configured for -# local-only mode. rhel9cis_is_mail_server: false -## Section 2.2 Service clients - -## Control - 2.2.1 - Ensure FTP client is not installed -# Set this variable to `true` to keep package `ftp`; otherwise, the package is uninstalled. +## Section 2.3 Service clients +# These toggles govern whether specific client packages are required on the system. +# false = package will be removed if present (CIS recommendation) +# true = package is required and will be left installed rhel9cis_ftp_client: false -## Control - 2.2.2 - Ensure LDAP client is not installed -# Set this variable to `true` to keep package `openldap-clients`; otherwise, the package is uninstalled. rhel9cis_openldap_clients_required: false -## Control - 2.2.3 - Ensure nis client is not installed -# Set this variable to `true` to keep package `nis`(`ypbind`); otherwise, the package is uninstalled. -rhel9cis_ypbind_required: false -## Control - 2.2.4 - Ensure telnet client is not installed -# Set this variable to `true` to keep package `telnet`; otherwise, the package is uninstalled. +rhel9cis_ypbind_required: false # Same package as NIS server rhel9cis_telnet_required: false -## Control - 2.2.5 - Ensure tftp client is not installed -# Set this variable to `true` to keep package `tftp`; otherwise, the package is uninstalled. rhel9cis_tftp_client: false ## Section 3 vars +## Sysctl +# Service configuration +# Options are +# Service +# - false - removes package +# - true - leaves package installed +# Mask +# - false - leaves service in current status +# - true - sets service name to masked +# +# Setting both Service and Mask to false will remove the package if exists +# +# Bluetooth service/mask - disabled by default as most servers do not require bluetooth +rhel9cis_bluetooth_service: false +rhel9cis_bluetooth_mask: false -## Control 3.1.1 - Ensure IPv6 status is identified +## 3.1 IPv6 requirement toggle # This variable governs whether ipv6 is enabled or disabled. rhel9cis_ipv6_required: true + +# 3.1.1 Disable IPv6 # rhel9cis_ipv6_disable defines the method of disabling IPv6, sysctl vs kernel rhel9cis_ipv6_disable_method: "sysctl" -## Control 3.1.2 - Ensure wireless interfaces are disabled +## 3.1.2 wireless network requirements # if wireless adapter found allow network manager to be installed rhel9cis_install_network_manager: false -# This variable holds the name of the network manager package, and it is used -# as a conditional to implement control 3.1.2. If the network manager package -# is present on the system then the control will be implemented! rhel9cis_network_manager_package_name: NetworkManager - -## Control 3.1.3 - Ensure bluetooth services are not in use -# Set this variable to `true` to keep service `bluetooth`; otherwise, the service is uninstalled. -rhel9cis_bluetooth_service: false -# Set this variable to `true` to mask service `bluetooth`. -rhel9cis_bluetooth_mask: false - -## Controls 3.3.x System network parameters (host only OR host and router) +# 3.3 System network parameters (host only OR host and router) # This variable governs whether specific CIS rules # concerned with acceptance and routing of packages are skipped. rhel9cis_is_router: false @@ -841,38 +777,37 @@ rhel9cis_flush_ipv4_route: false # NOTE: The current default value is likely to be overridden by other further tasks(via 'set_fact'). rhel9cis_flush_ipv6_route: false -## Section 4 vars - +# Section 4 vars ### Firewall Service to install and configure - Options are: # 1) either 'firewalld' # 2) or 'nftables' #### Some control allow for services to be removed or masked -#### The options are under each heading: +#### The options are under each heading #### absent = remove the package #### masked = leave package if installed and mask the service rhel9cis_firewall: firewalld -## Control 4.2.2 - Ensure firewalld loopback traffic is configured +## Control 4.2.x - Ensure firewalld default zone is set # This variable will set the firewalld default zone(that is used for everything that is not explicitly bound/assigned # to another zone): if there is no zone assigned to a connection, interface or source, only the default zone is used. rhel9cis_default_zone: public -## Controls 4.3.x -# This variable governs if a table will be automatically created in nftables. Without a table (no default one), nftables -# will not filter network traffic, so if this variable is set to 'false' and no tables exist, an alarm will be triggered! +## Controls 4.3.x nftables + +## 4.3.1 Ensure nftables base chains exist +# This variable governs if a nftables base chain(entry point for packets from the networking stack) will be automatically +# created, if needed. Without a chain, a hook for input, forward, and delete, packets that would flow through those +# chains will not be touched by nftables. +rhel9cis_nft_tables_autochaincreate: true + +## 4.3.2 Create tables if required rhel9cis_nft_tables_autonewtable: true # This variable stores the name of the table to be used when configuring nftables(creating chains, configuring loopback # traffic, established connections, default deny). If 'rhel9cis_nft_tables_autonewtable' is set as true, a new table will # be created using as name the value stored by this variable. rhel9cis_nft_tables_tablename: filter -## Control 4.3.1 - Ensure nftables base chains exist -# This variable governs if a nftables base chain(entry point for packets from the networking stack) will be automatically -# created, if needed. Without a chain, a hook for input, forward, and delete, packets that would flow through those -# chains will not be touched by nftables. -rhel9cis_nft_tables_autochaincreate: true - -## Section 5 vars +## Section5 vars ## Section 5.1 - SSH @@ -881,30 +816,32 @@ rhel9cis_nft_tables_autochaincreate: true # Otherwise, the default value is '/etc/ssh/ssh_config'. rhel9cis_sshd_config_file: /etc/ssh/sshd_config -## Control 5.1.7 - Ensure sshd access is configured +## Controls: +## - 5.1.7 - Ensure SSH access is limited # This variable, if specified, configures a list of USER name patterns, separated by spaces, to allow SSH # access for users whose user name matches one of the patterns. This is done # by setting the value of `AllowUsers` option in `/etc/ssh/sshd_config` file. # If an USER@HOST format will be used, the specified user will be allowed only on that particular host. rhel9cis_sshd_allowusers: "{% if ansible_facts.user_id != 'root' %}{{ ansible_facts.user_id }}{% elif ansible_env.SUDO_USER is defined %}{{ ansible_env.SUDO_USER }}{% endif %}" -## Control 5.1.7 - Ensure sshd access is configured + # (String) This variable, if specified, configures a list of GROUP name patterns, separated by spaces, to allow SSH access # for users whose primary group or supplementary group list matches one of the patterns. This is done # by setting the value of `AllowGroups` option in `/etc/ssh/sshd_config` file. rhel9cis_sshd_allowgroups: "" -## Control 5.1.7 - Ensure sshd access is configured + # This variable, if specified, configures a list of USER name patterns, separated by spaces, to prevent SSH access # for users whose user name matches one of the patterns. This is done # by setting the value of `DenyUsers` option in `/etc/ssh/sshd_config` file. # If an USER@HOST format will be used, the specified user will be restricted only on that particular host. rhel9cis_sshd_denyusers: "nobody" -## Control 5.1.7 - Ensure sshd access is configured + # This variable, if specified, configures a list of GROUP name patterns, separated by spaces, # to prevent SSH access for users whose primary group or supplementary group list matches one of the patterns. This is done # by setting the value of `DenyGroups` option in `/etc/ssh/sshd_config` file. rhel9cis_sshd_denygroups: "" -## Control 5.1.9 - Ensure sshd ClientAliveInterval and ClientAliveCountMax are configured +## - 5.1.9 - ClientAlive and CountMax +# default settings allow 45 seconds e.g. count x interval # This variable sets the maximum number of unresponsive "keep-alive" messages # that can be sent from the server to the client before the connection is considered # inactive and thus, closed. @@ -917,16 +854,14 @@ rhel9cis_sshd_clientaliveinterval: 15 ## Control 5.1.12 - disable forwarding # By Default this will also disable X11 forwarding # set 'yes' if x11 is required this can be changed to run in /etc/ssh/ssh_config.d/50-redhat.conf -# This variable's value is used in the `/etc/ssh/ssh_config.d/50-redhat.conf` file to -# disable X11Forwarding. If X11 is required, set this variable's value to `yes`! rhel9cis_sshd_x11forwarding: 'no' -## Control 5.1.14 - Ensure SSH LoginGraceTime is set to one minute or less +## - 5.1.14 - Ensure SSH LoginGraceTime is set to one minute or less # This variable specifies the amount of seconds allowed for successful authentication to # the SSH server. rhel9cis_sshd_logingracetime: 60 -## Control 5.1.15 - Ensure SSH LogLevel is appropriate +## Control 5.2.15 - Ensure SSH LogLevel is appropriate # This variable is used to control the verbosity of the logging produced by the SSH server. # The options for setting it are as follows: # - `QUIET`: Minimal logging; @@ -938,19 +873,19 @@ rhel9cis_sshd_logingracetime: 60 # - `DEBUG(x)`: Whereas x = debug level 1 to 3, DEBUG=DEBUG1. rhel9cis_ssh_loglevel: INFO -## Control 5.1.16 - Ensure sshd MaxAuthTries is configured +## Control 5.1.16 MaxAuthTries configured # The MaxAuthTries parameter specifies the maximum number of authentication # attempts permitted per connection. When the login failure count reaches half the # number, error messages will be written to the syslog file detailing the login failure. rhel9cis_ssh_maxauthtries: '4' -## Control 5.1.17 - Ensure sshd MaxStartups is configured +## Control 5.1.17 MaxStartups # The MaxStartups parameter specifies the maximum number of concurrent unauthenticated connections to the SSH daemon. rhel9cis_ssh_maxstartups: '10:30:60' -## Control 5.1.18 - Ensure sshd MaxSessions is configured +## Control 5.1.18 - Ensure SSH MaxSessions is set to 10 or less # This variable value specifies the maximum number of open sessions that are permitted from -# a given location. CIS recommends it to be 10 or less. +# a given location rhel9cis_ssh_maxsessions: 4 ## Control 5.2.x - Ensure sudo log file exists @@ -959,13 +894,6 @@ rhel9cis_ssh_maxsessions: 4 # This variable defines the path and file name of the sudo log file. rhel9cis_sudolog_location: "/var/log/sudo.log" -## Control 5.2.4 - Ensure users must provide password for escalation -# The following variable specifies a list of users that should not be required to provide a password -# for escalation. Feel free to edit it according to your needs. -rhel9cis_sudoers_exclude_nopasswd_list: - - ec2-user - - vagrant - ## Control 5.2.x - Ensure sudo authentication timeout is configured correctly # This variable sets the duration (in minutes) during which a user's authentication credentials # are cached after successfully authenticating using "sudo". This allows the user to execute @@ -973,37 +901,52 @@ rhel9cis_sudoers_exclude_nopasswd_list: # command within the specified time period. CIS requires a value of at most 15 minutes. rhel9cis_sudo_timestamp_timeout: 15 -## Control 5.2.7 - Ensure access to the 'su' command is restricted +## Control 5.2.4 +# This will leave NOPASSWD intact for these users +rhel9cis_sudoers_exclude_nopasswd_list: + - ec2-user + - vagrant + +## Control 5.2 - Ensure access to the 'su' command is restricted # This variable determines the name of the group of users that are allowed to use the su command. # CIS requires that such a group be CREATED(named according to site policy) and be kept EMPTY. rhel9cis_sugroup: sugroup -## Controls 5.3.x PAM and Authselect +## 5.3.x PAM and Authselect # Do not use authselect if: # Your host is part of Linux Identity Management. # Joining your host to an IdM domain with the ipa-client-install command automatically configures SSSD authentication on your host. # Your host is part of Active Directory via SSSD. # Calling the realm join command to join your host to an Active Directory domain automatically configures SSSD authentication on your host. rhel9cis_allow_authselect_updates: true -## Control 5.3.1.2 - Ensure latest version of authselect is installed -# The following variables controls the implementation of control 5.3.1.2. -# If you want the latest version to be installed set this variable's value -# to `true`. +## rhel9cis_authselect_pkg_update: false # NOTE the risks if system is using SSSD or using ipa-client-install ## PAM AND Authselect -## Controls 5.3.x +# To create a new profile (best for greenfield fresh sites not configured) +# This allows creation of a custom profile using an existing one to build from +# will only create if profile does not already exist +## options true or false +rhel9cis_authselect_custom_profile_create: true +## Controls: +# - 5.3.2.1 - Ensure custom authselect profile is used +# Settings in place now will fail, they are placeholders from the control example. Due to the way many multiple +# options and ways to configure this control needs to be enabled and settings adjusted to minimize risk. # This variable configures the name of the custom profile to be created and selected. -# To be changed from default - cis_example_profile. This setting needs to be adjusted -# in order to minimise risk. +# To be changed from default - cis_example_profile rhel9cis_authselect_custom_profile_name: cis_example_profile # Name of the existing authselect profile to copy - options can be found with # ```authselect list``` on the host to be configured rhel9cis_authselect_default_profile_to_copy: "sssd --symlink-meta" -## Control 5.3.3.1.1 - +## Controls +# - 5.3.3. - Ensure lockout for failed password attempts is configured +# - 5.5.3 - Ensure password reuse is limited +# - 5.5.4 - Ensure password hashing algorithm is SHA-512 +# - 5.4.2 - Ensure authselect includes with-faillock +# - 5.3.3.1.1 # This variable sets the amount of tries a password can be entered, before a user is locked. rhel9cis_pam_faillock_deny: 5 @@ -1038,120 +981,83 @@ rhel9cis_root_unlock_time: 60 # ######################################################################################################################## -## Control 5.3.3.2.1 - Ensure password number of changed characters is configured -# This variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure password number of changed characters is configured' control. +# 5.3.3.2.1 - password difok rhel9cis_passwd_difok_file: etc/security/pwquality.conf.d/50-pwdifok.conf # pragma: allowlist secret -# This variable's value represents the minimum number of characters that must be different between -# the new password and the old password. It helps ensure that users don't create new passwords that -# are too similar to their previous ones, enhancing security. CIS states that this value should be at least 2. rhel9cis_passwd_difok_value: 2 -## Control 5.3.3.2.2 - Ensure minimum password length is configured -# This variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure minimum password length is configured' control. +# 5.3.3.2.2 - password minlength rhel9cis_passwd_minlen_file: etc/security/pwquality.conf.d/50-pwlength.conf # pragma: allowlist secret -# This variable specifies the minimum length that a password must have to be considered valid. -# CIS states that this value should be at least 14. rhel9cis_passwd_minlen_value: 14 -## Control 5.3.3.2.3 - Ensure password complexity is configured -# The following variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure password complexity is configured' control. +# 5.3.3.2.3 - password complex rhel9cis_passwd_complex_file: etc/security/pwquality.conf.d/50-pwcomplexity.conf # pragma: allowlist secret -# This variable holds the options for configuring the password complexity. -# Options supported are: 'minclass' or 'credits'. +# Choose if using minclass or credits options +# Options are: minclass or credits +# ensure only one is selected rhel9cis_passwd_complex_option: minclass # pragma: allowlist secret -# The following variable sets the password complexity via 'minclass'. The 'minclass' option provides -# the minimum number of classes of characters required in a new password. (digits, uppercase, lowercase, others). e.g. -# For example a value of 4 would mean that it requires digits, uppercase, lower case, and special characters. rhel9cis_passwd_minclass: 4 -# The following variables set the password complexity via the 'credits' option. -# Each of the variables represents a requirement for complexity. -# The 'dcredit' variable is the maximum credit for having digits in the new password. -# If less than 0 it is the minimum number of digits in the new password. -# e.g. dcredit = -1 requires at least one digit +# rhel9cis_passwd_complex: credits rhel9cis_passwd_dcredit: -1 -# The 'ucredit' variable is the maximum credit for having uppercase characters in the new password. -# If less than 0 it is the minimum number of uppercase characters in the new password. -# e.g. ucredit = -1 requires at least one uppercase character rhel9cis_passwd_ucredit: -2 -# The 'ocredit' variable is the maximum credit for having other characters in the new password. -# If less than 0 it is the minimum number of other characters in the new password. -# e.g. ocredit = -1 requires at least one special character rhel9cis_passwd_ocredit: 0 -# The 'lcredit' variable is the maximum credit for having lowercase characters in the new password. -# If less than 0 it is the minimum number of lowercase characters in the new password. -# e.g. lcredit = -1 requires at least one lowercase character rhel9cis_passwd_lcredit: -2 -## Control 5.3.3.2.4 - Ensure password same consecutive characters is configured -# This variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure password same consecutive characters is configured' control. +# 5.3.3.2.4 - password maxrepeat rhel9cis_passwd_maxrepeat_file: etc/security/pwquality.conf.d/50-pwrepeat.conf # pragma: allowlist secret -# The following variable sets the maximum number of allowed same consecutive characters in a new password. rhel9cis_passwd_maxrepeat_value: 3 -## Control 5.3.3.2.5 - Ensure password maximum sequential characters is configured -# This variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure password maximum sequential characters is configured' control. +# 5.3.3.2.5 - password maxsequence rhel9cis_passwd_maxsequence_file: etc/security/pwquality.conf.d/50-pwmaxsequence.conf # pragma: allowlist secret -# The following variable sets the maximum length of monotonic character sequences in the new password. -# Examples of such sequence are '12345' or 'fedcb' . The check is disabled if the value is 0 . rhel9cis_passwd_maxsequence_value: 3 -## Control 5.3.3.2.6 - Ensure password dictionary check is enabled -# This variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure password dictionary check is enabled' control +# 5.3.3.2.6 - password dictcheck rhel9cis_passwd_dictcheck_file: etc/security/pwquality.conf.d/50-pwdictcheck.conf # pragma: allowlist secret -# The following variable's value sets whether to check for the words from the cracklib dictionary. -# When set to '1', this option enables dictionary checks, ensuring that passwords are not based on common -# dictionary words, which helps prevent users from choosing easily guessable passwords. -# When set to '0', dictionary checks are disabled. CIS states that it shall always be set to '1'. rhel9cis_passwd_dictcheck_value: 1 # 5.3.3.2.7 - Ensure password quality is enforced for the root user -rhel9cis_passwd_quality_enforce_file: etc/security/pwquality.conf.d/50-pwroot.conf # pragma: allowlist secret +rhel9cis_passwd_quality_enforce_file: etc/security/pwquality.conf.d/50-pwquality_enforce.conf # pragma: allowlist secret rhel9cis_passwd_quality_enforce_value: 1 rhel9cis_passwd_quality_enforce_root_value: enforce_for_root # pragma: allowlist secret -## Control 5.3.3.3.1 - Ensure password history remember is configured -# This variable represents the number of password change cycles, after which -# a user can re-use a password. CIS requires a value of 24 or more. +# PWhistory +## 5.3.3.3.1 remember history +# rhel9cis_pamd_pwhistory_remember: - is the number of old passwords to remember rhel9cis_pamd_pwhistory_remember: 24 -## Controls 5.3.3.4.3, 5.4.1.4 -# The following variable's value represents the hashing algorithm used +# 5.3.3.4.x rhel9cis_passwd_hash_algo: sha512 # pragma: allowlist secret ## Control 5.4.1.1 - Ensure password expiration is 365 days or less # This variable governs after how many days a password expires. # CIS requires a value of 365 or less. rhel9cis_pass_max_days: 365 -# The following variable allows the forcing of setting user_max_days for logins. -# This can break current connecting user access -rhel9cis_force_user_maxdays: false -## Control 5.4.1.2 - Ensure minimum days between password changes is 7 or more +## Control 5.4.1.2 - Ensure minimum days between password change can be 7 or more # This variable specifies the minimum number of days allowed between changing # passwords. CIS requires a value of at least 1. rhel9cis_pass_min_days: 7 -# The following variable allows the force setting of minimum days between changing the password -# This can break current connecting user access -rhel9cis_force_user_mindays: false ## Control 5.4.1.3 - Ensure password expiration warning days is 7 or more # This variable governs, how many days before a password expires, the user will be warned. # CIS requires a value of at least 7. rhel9cis_pass_warn_age: 7 -# The following variable allows the forcing of number of days before warning users of password expiry -# This can break current connecting user access -rhel9cis_force_user_warnage: false -## Control 5.4.1.5 - Ensure inactive password lock is configured +## Control 5.4.1.x - Ensure inactive password lock is 30 days or less rhel9cis_inactivelock: # This variable specifies the number of days of inactivity before an account will be locked. # CIS requires a value of 30 days or less. lock_days: 30 +## 5.4.1.x Allow the forcing of setting user_max_days for logins. +# This can break current connecting user access +rhel9cis_force_user_maxdays: false + +## 5.4.1.x Allow the force setting of minimum days between changing the password +# This can break current connecting user access +rhel9cis_force_user_mindays: false + +## 5.4.1.x Allow the forcing of number of days before warning users of password expiry +# This can break current connecting user access +rhel9cis_force_user_warnage: false + ## Control 5.4.1.x - Ensure all users last password change date is in the past # Allow ansible to expire password for account with a last changed date in the future. Setting it # to 'false' will just display users in violation, while 'true' will expire those users passwords. @@ -1188,37 +1094,52 @@ rhel9cis_shell_session_timeout: 900 # - `/etc/bash.bashrc`. rhel9cis_shell_session_file: /etc/profile.d/tmout.sh -## Control 5.4.3.3 - Ensure default user umask is configured -# The following variable specifies the "umask" to set in the `/etc/bash.bashrc` and `/etc/profile`. -# The value needs to be `027` or more restrictive to comply with CIS standards. +## Control 5.4.3.2 bash umask rhel9cis_bash_umask: '0027' # 0027 or more restrictive -## Section 6 vars +### Controls: +# - 5.6.2 - Ensure system accounts are secured +# - 6.2.10 - Ensure local interactive user home directories exist +# - 6.2.11 - Ensure local interactive users own their home directories +# UID settings for interactive users +# These are discovered via logins.def if set true +rhel9cis_discover_int_uid: true +# This variable sets the minimum number from which to search for UID +# Note that the value will be dynamically overwritten if variable `rhel9cis_discover_int_uid` has +# been set to `true`. +min_int_uid: 1000 +### Controls: +# - Ensure local interactive user home directories exist +# - Ensure local interactive users own their home directories +# This variable sets the maximum number at which the search stops for UID +# Note that the value will be dynamically overwritten if variable `rhel9cis_discover_int_uid` has +# been set to `true`. +max_int_uid: 65533 -## Control 6.1.1 - Ensure AIDE is installed +## Section6 vars +## Control 6.1.x - allow aide to be configured # AIDE is a file integrity checking tool, similar in nature to Tripwire. # While it cannot prevent intrusions, it can detect unauthorized changes # to configuration files by alerting when the files are changed. Review # the AIDE quick start guide and AIDE documentation before proceeding. -# By setting this variable to `true`, all the settings related to AIDE -# will be applied! +# By setting this variable to `true`, all of the settings related to AIDE will be applied! rhel9cis_config_aide: true -# This variable sets a maximum allowed age of the AIDE database file until -# the file is rebuilt. If the file is older than the value below, the role -# will automatically rebuild the database file. + +# If DB file older than below will automatically rebuild DB # e.g. options:1w = 1 week, 1d = 1day 1h = 1 hour rhel9cis_aide_db_file_age: 1w -# If AIDE is already setup this variable forces a new database -# file to be created. + +# If aide already setup this forces a new DB to be created rhel9cis_aide_db_recreate: false # allows changing the db file; note the config needs to be adjusted too rhel9cis_aide_db_file: /var/lib/aide/aide.db.gz -## Control 6.1.2 - Ensure filesystem integrity is regularly checked -# The following variable sets how AIDE is scanned. -# Available options are either cron or timer. +## Control 6.1.2 AIDE cron settings + +## How the aide schedule is run either cron or timer rhel9cis_aide_scan: cron + # These are the crontab settings for periodical checking of the filesystem's integrity using AIDE. # The sub-settings of this variable provide the parameters required to configure # the cron job on the target system. @@ -1254,15 +1175,17 @@ rhel9cis_aide_cron: # can be given in the range `0-7` (both `0` and `7` represent Sunday); several weekdays # can be concatenated with commas. aide_weekday: '*' - +# ## Preferred method of logging +## Whether rsyslog or journald preferred method for local logging ## Controls 6.2.1.x | Configure systemd-journald service ## Controls 6.2.2.x | Configured journald ## Controls 6.2.3.x | Configure rsyslog + # This variable governs which logging service should be used, choosing between 'rsyslog' # or 'journald'(CIS recommendation) will trigger the execution of the associated subsection, as the-best # practices are written wholly independent of each other. -rhel9cis_syslog: rsyslog +rhel9cis_syslog: journald ## Control 6.2.1.3 - Ensure journald log rotation is configured per site policy # Current variable configures the max amount of disk space the logs will use(thus, journal files @@ -1293,31 +1216,36 @@ rhel9cis_journald_runtimekeepfree: 100G # ATTENTION: Uncomment the keyword below when values are set! rhel9cis_journald_maxfilesec: 1month -## Control 6.2.2.1.2 - Ensure systemd-journal-upload authentication is configured +## Control 6.2.2.1.2 - Ensure systemd-journal-remote is configured # 'rhel9cis_journal_upload_url' is the ip address to upload the journal entries to # URL value may specify either just the hostname or both the protocol and hostname. 'https' is the default. The port # number may be specified after a colon (":"), otherwise 19532 will be used by default. rhel9cis_journal_upload_url: 192.168.50.42 +## The paths below have the default paths/files, but allow user to create custom paths/filenames + ## Control 6.2.2.1.2 - Ensure systemd-journal-remote is configured # This variable specifies the path to the private key file used by the remote journal # server to authenticate itself to the client. This key is used alongside the server's -# public certificate to establish secure communication. The path below has the default -# path/file, but it is also allowed for a user to create its custom path/filename. +# public certificate to establish secure communication. rhel9cis_journal_upload_serverkeyfile: "/etc/ssl/private/journal-upload.pem" ## Control 6.2.2.1.2 - Ensure systemd-journal-remote is configured # This variable specifies the path to the public certificate file of the remote journal -# server. This certificate is used to verify the authenticity of the remote server. The path -# below has the default path/file, but it is also allowed for a user to create its custom -# path/filename. +# server. This certificate is used to verify the authenticity of the remote server. rhel9cis_journal_servercertificatefile: "/etc/ssl/certs/journal-upload.pem" ## Control 6.2.2.1.2 - Ensure systemd-journal-remote is configured # This variable specifies the path to a file containing one or more public certificates # of certificate authorities (CAs) that the client trusts. These trusted certificates are used -# to validate the authenticity of the remote server's certificate. The path below has the default -## path/file, but it is also allowed for a user to create its custom path/filename. +# to validate the authenticity of the remote server's certificate. rhel9cis_journal_trustedcertificatefile: "/etc/ssl/ca/trusted.pem" # ATTENTION: Uncomment the keyword below when values are set! +# Control 6.2.3.x - Ensure rsyslog is not configured to receive logs from a remote client +# This variable expresses whether the system is used as a log server or not. If set to: +# - 'false', current system will act as a log CLIENT, thus it should NOT receive data from other hosts. +# - 'true', current system will act as a log SERVER, enabling centralised log management(by protecting log integrity +# from local attacks on remote clients) +rhel9cis_system_is_log_server: false + ## Control 6.2.3.5 | PATCH | Ensure logging is configured # This variable governs if current Ansible role should manage syslog settings # in /etc/rsyslog.conf file, namely mail, news and misc(warn, messages) @@ -1359,40 +1287,27 @@ rhel9cis_remote_log_retrycount: 100 # of rsyslog forwarding must be enabled('rhel9cis_remote_log_server: true'). rhel9cis_remote_log_queuesize: 1000 -## Control 6.2.3.7 - Ensure rsyslog is not configured to receive logs from a remote client -# This variable expresses whether the system is used as a log server or not. If set to: -# - 'false', current system will act as a log CLIENT, thus it should NOT receive data from other hosts. -# - 'true', current system will act as a log SERVER, enabling centralised log management(by protecting log integrity -# from local attacks on remote clients) -rhel9cis_system_is_log_server: false - ## Control 6.2.3.8 rsyslog rotate -# This variable configures whether to set your own rsyslog logrotate setting -# alternate to logrotate default settings. Please refer to logrotate options -# to match your site requirements -# This variable sets when to rotate +# This variable configures whether to set your own rsyslog logrotate setting alternate to logrotate default settings +# Please refer to logrotate options to match your site requirements +# This sets when to rotate rhel9cis_rsyslog_logrotate_rotated_when: weekly -# This variable sets how many rotations of the file to keep +# This sets how many rotations of the file to keep rhel9cis_rsyslog_logrotate_rotatation_keep: 4 -# The following variable defines whether to set the compress option -# or not. Setting it to `true` will carry out the setting. +# This defines whether to set various options or not +# these are taken from logrotate options +# Setting +# true will carry out the setting. +# false will either set no/not or not add the option rhel9cis_rsyslog_logrotate_compress: true -# The following variable defines whether to set the missingok option -# or not. Setting it to `true` will carry out the setting. rhel9cis_rsyslog_logrotate_missingok: true -# The following variable defines whether to set the notifempty option -# or not. Setting it to `true` will carry out the setting. rhel9cis_rsyslog_logrotate_notifempty: true -# The following variable defines whether to set extra options that can -# be defined in the `rhel9cis_rsyslog_logrotate_create_opts` variable -# The variable can be found underneath this variable, in a commented -# state. rhel9cis_rsyslog_logrotate_create: true # Extra options that can be added according to rsyslog documentation # Uncomment and add the required options e.g. mode owner group # rhel9cis_rsyslog_logrotate_create_opts: -## Control 6.3.1.3 - Ensure audit_backlog_limit is sufficient +## Control 6.3.2.1 - Ensure audit_backlog_limit is sufficient # This variable represents the audit backlog limit, i.e., the maximum number of audit records that the # system can buffer in memory, if the audit subsystem is unable to process them in real-time. # Buffering in memory is useful in situations, where the audit system is overwhelmed @@ -1401,17 +1316,16 @@ rhel9cis_rsyslog_logrotate_create: true rhel9cis_audit_back_log_limit: 8192 ## Controls 6.3.2.x - What to do when log files fill up - ## Control 6.3.2.1 - Ensure audit log storage size is configured # This variable specifies the maximum size in MB that an audit log file can reach # before it is archived or deleted to make space for the new audit data. # This should be set based on your sites policy. CIS does not provide a specific value. rhel9cis_auditd_max_log_file_size: 10 -## Control 6.3.2.2 - Ensure audit logs are not automatically deleted +## Control 6.3.2.2 # This variable determines what action the audit system should take when the maximum # size of a log file is reached. -# The options for setting this variable are as follows: +# The variable can have the following possible values: # - `ignore`: the system does nothing when the size of a log file is full; # - `syslog`: a message is sent to the system log indicating the problem; # - `suspend`: the system suspends recording audit events until the log file is cleared or rotated; @@ -1420,66 +1334,39 @@ rhel9cis_auditd_max_log_file_size: 10 # CIS prescribes the value `keep_logs`. rhel9cis_auditd_max_log_file_action: keep_logs -## Control 6.3.2.3 - Ensure system is disabled when audit logs are full -# This variable determines how the system should act in case of issues with the disk. -# The disk_full_action parameter tells the system what action to take when no free space is -# available on the partition that holds the audit log files. +## Control 6.3.2.3 +# This variable determines how the system should act in case of issues with disk +# The disk_full_action parameter tells the system what action to take when no free space is available on the partition that holds the audit log files. # Valid values are ignore, syslog, rotate, exec, suspend, single, and halt. +# +# The disk_error_action parameter tells the system what action to take when an error is detected on the partition that holds the audit log files. +# Valid values are ignore, syslog, exec, suspend, single, and halt. +# # CIS prescribes # disk_full_action parameter: -# Set to halt - the auditd daemon will shutdown the system when the disk partition containing -# the audit logs becomes full. -# Set to single - the auditd daemon will put the computer system in single user mode when the -# disk partition containing the audit logs becomes full. -rhel9cis_auditd_disk_full_action: halt -# This variable determines how the system should act in case of issues with the disk. -# The disk_error_action parameter tells the system what action to take when an error is detected -# on the partition that holds the audit log files. -# Valid values are ignore, syslog, exec, suspend, single, and halt. +# Set to halt - the auditd daemon will shutdown the system when the disk partition containing the audit logs becomes full. +# Set to single - the auditd daemon will put the computer system in single user mode when the disk partition containing the audit logs becomes full. +# # disk_error_action parameter: -# Set to halt - the auditd daemon will shutdown the system when an error is detected on the -# partition that holds the audit log files. -# Set to single - the auditd daemon will put the computer system in single user mode when -# an error is detected on the partition that holds the audit log files. -# Set to syslog - the auditd daemon will issue no more than 5 consecutive warnings to syslog -# when an error is detected on the partition that holds the audit log files. +# Set to halt - the auditd daemon will shutdown the system when an error is detected on the partition that holds the audit log files. +# Set to single - the auditd daemon will put the computer system in single user mode when an error is detected on the partition that holds the audit log files. +# Set to syslog - the auditd daemon will issue no more than 5 consecutive warnings to syslog when an error is detected on the partition that holds the audit log files. +rhel9cis_auditd_disk_full_action: halt rhel9cis_auditd_disk_error_action: syslog -## Control 6.3.2.4 - Ensure system warns when audit logs are low on space -# This variable tells the system what action to take when the system has detected -# that it is starting to get low on disk space. -# The options for setting this variable are as follows: -# "ignore" - the system does nothing when presented with the aforementioned issue; -# "syslog" - a message is sent to the system log about disk space running low; -# "email" - the system sends an email notification to the email address -# specified in the "action_mail_acct" variable; -# "exec" - the system executes a custom command when disk space is running -# low; -# "suspend" - the system suspends recording audit events until more space is available; -# "single" - the audit daemon will put the computer system in single user mode; -# "halt" - the system is halted when disk space is critically low; -# CIS prescribes either 'email', 'exec', `single` or `halt`. +# Control 6.3.2.4 +# Wait to do when space left is low. +# The space_left_action parameter tells the system what action to take when the system has detected that it is starting to get low on disk space. +# Valid values are ignore, syslog, rotate, email, exec, suspend, single, and halt. +# The admin_space_left_action parameter tells the system what action to take when the system has detected that it is low on disk space. +# Valid values are ignore, syslog, rotate, email, exec, suspend, single, and halt. rhel9cis_auditd_space_left_action: email -# This variable tells the system what action to take when the system has detected -# that it is low on disk space. -# The options for setting this variable are as follows: -# "ignore" - the system does nothing when presented with the aforementioned issue; -# "syslog" - a message is sent to the system log about disk space running low; -# "email" - the system sends an email notification to the email address -# specified in the "action_mail_acct" variable; -# "exec" - the system executes a custom command when disk space is running -# low; -# "suspend" - the system suspends recording audit events until more space is available; -# "single" - the audit daemon will put the computer system in single user mode; -# "halt" - the system is halted when disk space is critically low; -# CIS prescribes either `halt` or `single`. rhel9cis_auditd_admin_space_left_action: halt -# This value governs if the below extra-vars (found in the `rhel9cis_auditd_extra_conf`) -# for auditd should be used by the role. +# This value governs if the below extra-vars for auditd should be used by the role rhel9cis_auditd_extra_conf_usage: false -## Controls 6.3.3.x allow exceptions for UID in auditd config +# 6.3.3.x allow exceptions for UID in auditd config ## Advanced option found in auditd post # This variable governs if defining user exceptions for auditd logging is acceptable. rhel9cis_allow_auditd_uid_user_exclusions: false @@ -1488,27 +1375,18 @@ rhel9cis_auditd_uid_exclude: - 1999 # This can be used to configure other keys in auditd.conf +# Example: rhel9cis_auditd_extra_conf: - # This variable governs the threshold(MegaBytes) under which the audit daemon should perform a - # specific action to alert that the system is running low on disk space. Must be lower than - # the 'space_left' variable. admin_space_left: '10%' # Section 7 Vars -## Control 7.1.11 - Ensure no world writable files exist -# The following variable is a toggle for enabling/disabling the automated -# removal of world-writable permissions from all files. -# Possible values are `true` and `false`. -rhel9cis_no_world_write_adjust: true +# 7.1.12 Ensure no files or directories without an owner and a group exist +rhel9cis_exclude_unowned_search_path: \( ! -path "/run/user/*" -a ! -path "/proc/*" -a ! -path "*/containerd/*" -a ! -path "*/kubelet/pods/*" -a ! -path "*/kubelet/plugins/*" -a ! -path "/sys/fs/cgroup/memory/*" -a ! -path "/var/*/private/*" \) -## Control 7.1.12 - Ensure no files or directories without an owner and a group exist -# This variable holds the part of the command that helps detect which files and -# directories do not have an owner and an affiliated group. -rhel9cis_exclude_unowned_search_path: (! -path "/run/user/*" -a ! -path "/proc/*" -a ! -path "*/containerd/*" -a ! -path "*/kubelet/pods/*" -a ! -path "*/kubelet/plugins/*" -a ! -path "/sys/fs/cgroup/memory/*" -a ! -path "/var/*/private/*") +# Control 7.1.12 # The value of this variable specifies the owner that will be set for unowned files and directories. rhel9cis_unowned_owner: root -# The value of this variable specifies the group that will be set for ungrouped files and directories. rhel9cis_ungrouped_group: root # This variable is a toggle for enabling/disabling the automated # setting of an owner (specified in variable `rhel9cis_unowned_owner`) @@ -1516,28 +1394,17 @@ rhel9cis_ungrouped_group: root # Possible values are `true` and `false`. rhel9cis_ownership_adjust: true -## Control 7.1.13 - Ensure SUID and SGID files are reviewed +## Control 7.1.13 # This variable is a toggle for enabling/disabling the automated removal # of the SUID bit from all files on all mounts. # Possible values are `true` and `false`. rhel9cis_suid_sgid_adjust: false -## Control 7.2.8 - Ensure local interactive user home directories are configured -# UID settings for interactive users -# These are discovered via logins.def if set true -rhel9cis_discover_int_uid: true -# This variable sets the minimum number from which to search for UID -# Note that the value will be dynamically overwritten if variable `rhel9cis_discover_int_uid` has -# been set to `true`. -min_int_uid: 1000 -# This variable sets the maximum number at which the search stops for UID -# Note that the value will be dynamically overwritten if variable `rhel9cis_discover_int_uid` has -# been set to `true`. -max_int_uid: 65533 +## Control 7.1.11 - Ensure no world writable files exist +# Allow ansible to adjust world-writable files. False will just display world-writable files, True will remove world-writable. +rhel9cis_no_world_write_adjust: true -## Control 7.2.9 - Ensure local interactive user dot files access is configured -# This variable is a toggle for enabling/disabling the automated modification of -# permissions on dot files. -# Possible values are `true` and `false` -# This setting can impact a running system if not tested sufficiently +## Control 7.2.9 +# This allows ansible to alter the dot files as per rule if found +# When set to true this will align with benchmark - can impact a running system if not tested sufficiently rhel9cis_dotperm_ansiblemanaged: false diff --git a/tasks/LE_audit_setup.yml b/tasks/LE_audit_setup.yml index 53293e7..099ed41 100644 --- a/tasks/LE_audit_setup.yml +++ b/tasks/LE_audit_setup.yml @@ -25,7 +25,7 @@ - name: Pre Audit Setup | Copy audit binary when: get_audit_binary_method == 'copy' ansible.builtin.copy: - src: "{{ audit_bin_copy_location }}/goss-linux-{{ audit_pkg_arch_name }}" + src: "{{ audit_bin_copy_location }}" dest: "{{ audit_bin }}" owner: root group: root diff --git a/tasks/auditd.yml b/tasks/auditd.yml index 9ada459..fa48233 100644 --- a/tasks/auditd.yml +++ b/tasks/auditd.yml @@ -3,59 +3,47 @@ # Since auditd rules are dependent on syscalls and syscall tables are architecture specific, # we need to update the auditd rules depending on the architecture of the system. # This task passed the syscalls table to the auditd template and updates the auditd rules - - name: "POST | AUDITD | Set supported_syscalls variable" ansible.builtin.shell: ausyscall --dump | awk '{print $2}' changed_when: false - check_mode: false failed_when: discovered_auditd_syscalls.rc not in [ 0, 1 ] register: discovered_auditd_syscalls -- name: POST | AUDITD | Apply auditd template will for section 6.3.3 - only required rules will be added | stat file - ansible.builtin.stat: - path: /etc/audit/rules.d/99_auditd.rules - register: discovered_auditd_rules_file +- name: "POST | AUDITD | Ensure use of privileged commands is collected" + ansible.builtin.shell: | + {%- set egrep_exclude = "(asdfmnop|{{ rhel9cis_priv_command_excluded_mounts | join('|') }})" -%} + for i in $(df | grep '^/dev' | grep -Ev '{{ egrep_exclude }}' | awk '{ print $NF }'); do + find $i -xdev -type f -perm /6000 2>/dev/null; + done + changed_when: false + failed_when: false + check_mode: false + register: discovered_privileged_commands -- name: POST | Apply auditd template for section 6.3.3.x +- name: "POST | AUDITD | Apply auditd template for section 6.2.4.x" when: update_audit_template vars: supported_syscalls: "{{ discovered_auditd_syscalls.stdout_lines }}" ansible.builtin.template: - src: audit/99_auditd.rules.j2 + src: etc/audit/rules.d/99_auditd.rules.j2 dest: /etc/audit/rules.d/99_auditd.rules owner: root group: root - mode: 'u-x,g-wx,o-rwx' - diff: "{{ discovered_auditd_rules_file.stat.exists }}" # Only run diff if not a new file - register: discovered_auditd_rules_template_updated + mode: 'u-x,go-wx' + register: discovered_audit_rules_updated notify: - - Auditd immutable check - - Audit immutable fact + - Auditd rules reload - Restart auditd -- name: POST | AUDITD | Add Warning count for changes to template file | Warn Count # noqa no-handler - when: - - discovered_auditd_rules_template_updated.changed - - discovered_auditd_rules_file.stat.exists - ansible.builtin.import_tasks: - file: warning_facts.yml - vars: - warn_control_id: 'Auditd template updated, validate as expected' - -- name: POST | AUDITD | Apply auditd template will for section 4.1.3 - only required rules will be added | stat file - ansible.builtin.stat: - path: /etc/audit/rules.d/98_auditd_exceptions.rules - register: discovered_auditd_exception_file - -- name: POST | Set up auditd user logging exceptions | setup file - when: - - rhel9cis_allow_auditd_uid_user_exclusions - - rhel9cis_auditd_uid_exclude | length > 0 +- name: POST | AUDITD | Set up auditd user logging exceptions + when: rhel9cis_allow_auditd_uid_user_exclusions ansible.builtin.template: - src: audit/98_auditd_exception.rules.j2 + src: etc/audit/rules.d/98_auditd_exception.rules.j2 dest: /etc/audit/rules.d/98_auditd_exceptions.rules owner: root group: root - mode: '0640' - diff: "{{ discovered_auditd_exception_file.stat.exists }}" + mode: 'u-x,go-rwx' notify: Restart auditd + +- name: POST | AUDITD | Flush handlers + ansible.builtin.meta: flush_handlers diff --git a/tasks/main.yml b/tasks/main.yml index fe3b9b9..34af483 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -200,15 +200,13 @@ file: auditd.yml - name: "Run post remediation tasks" - tags: - - post_tasks - - always + tags: always ansible.builtin.import_tasks: file: post.yml -- name: "Run post_remediation audit" +- name: "Run post remediation audit" when: run_audit - tags: always + tags: run_audit ansible.builtin.import_tasks: file: post_remediation_audit.yml diff --git a/tasks/post_remediation_audit.yml b/tasks/post_remediation_audit.yml index 5e9419c..cd33220 100644 --- a/tasks/post_remediation_audit.yml +++ b/tasks/post_remediation_audit.yml @@ -1,6 +1,6 @@ --- -- name: Post Audit | Run post_remediation {{ benchmark }} audit # noqa name[template] +- name: Post Audit | Run post_remediation {{ benchmark }} audit # noqa name[template] ansible.builtin.shell: "umask 0022 && {{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -m {{ audit_max_concurrent }} -o {{ post_audit_outfile }} -g \"{{ group_names }}\"" # noqa yaml[line-length] changed_when: true environment: @@ -14,11 +14,11 @@ - name: Post Audit | Capture audit data if json format ansible.builtin.shell: grep -E '"summary-line.*Count:.*Failed' "{{ post_audit_outfile }}" | cut -d'"' -f4 changed_when: false - register: post_audit_summary + register: post_audit_summary_json - name: Post Audit | Set Fact for audit summary ansible.builtin.set_fact: - post_audit_results: "{{ post_audit_summary.stdout }}" + post_audit_results: "{{ post_audit_summary_json.stdout }}" - name: Post Audit | Capture audit data if documentation format when: audit_format == "documentation" @@ -26,8 +26,8 @@ - name: Post Audit | Capture audit data if documentation format ansible.builtin.shell: tail -2 "{{ post_audit_outfile }}" | tac | tr '\n' ' ' changed_when: false - register: post_audit_summary + register: post_audit_summary_documentation - name: Post Audit | Set Fact for audit summary ansible.builtin.set_fact: - post_audit_results: "{{ post_audit_summary.stdout }}" + post_audit_results: "{{ post_audit_summary_documentation.stdout }}" diff --git a/tasks/pre_remediation_audit.yml b/tasks/pre_remediation_audit.yml index 410473e..c876749 100644 --- a/tasks/pre_remediation_audit.yml +++ b/tasks/pre_remediation_audit.yml @@ -6,7 +6,7 @@ ansible.builtin.include_tasks: file: LE_audit_setup.yml -- name: Pre Audit Setup | Ensure existence of {{ audit_conf_dir }} # noqa name[template] +- name: Pre Audit Setup | Ensure existence of {{ audit_conf_dir }} # noqa name[template] ansible.builtin.file: path: "{{ audit_conf_dir }}" mode: 'go-w' @@ -71,8 +71,8 @@ dest: "{{ audit_vars_path }}" mode: 'go-rwx' -- name: Pre Audit | Run pre_remediation audit {{ benchmark }} # noqa name[template] - ansible.builtin.shell: "umask 0022 && {{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -m {{ audit_max_concurrent }} -o {{ pre_audit_outfile }} -g \"{{ group_names }}\"" # noqa yaml[line-length] +- name: Pre Audit | Run pre_remediation audit {{ benchmark }} # noqa name[template] + ansible.builtin.shell: "umask 0022 && {{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -m {{ audit_max_concurrent }} -o {{ pre_audit_outfile }} -g \"{{ group_names }}\"" # noqa yaml[line-length] changed_when: true environment: AUDIT_BIN: "{{ audit_bin }}" @@ -85,12 +85,11 @@ - name: Pre Audit | Capture audit data if json format ansible.builtin.shell: grep -E '\"summary-line.*Count:.*Failed' "{{ pre_audit_outfile }}" | cut -d'"' -f4 changed_when: false - failed_when: pre_audit_summary.stderr | length > 0 - register: pre_audit_summary + register: pre_audit_summary_json - name: Pre Audit | Set Fact for audit summary ansible.builtin.set_fact: - pre_audit_results: "{{ pre_audit_summary.stdout }}" + pre_audit_results: "{{ pre_audit_summary_json.stdout }}" - name: Pre Audit | Capture audit data if documentation format when: audit_format == "documentation" @@ -98,12 +97,11 @@ - name: Pre Audit | Capture audit data if documentation format ansible.builtin.shell: tail -2 "{{ pre_audit_outfile }}" | tac | tr '\n' ' ' changed_when: false - failed_when: pre_audit_summary.stderr | length > 0 - register: pre_audit_summary + register: pre_audit_summary_documentation - name: Pre Audit | Set Fact for audit summary ansible.builtin.set_fact: - pre_audit_results: "{{ pre_audit_summary.stdout }}" + pre_audit_results: "{{ pre_audit_summary_documentation.stdout }}" - name: Audit_Only | Run Audit Only when: audit_only diff --git a/tasks/prelim.yml b/tasks/prelim.yml index 91e576d..44c49b3 100644 --- a/tasks/prelim.yml +++ b/tasks/prelim.yml @@ -295,6 +295,13 @@ state: directory mode: 'u+x,g-w,o-rwx' +- name: "PRELIM | AUDIT | Discover if auditd is immutable" + tags: always + ansible.builtin.command: grep -c "^-e 2" /etc/audit/rules.d/99_auditd.rules + changed_when: false + failed_when: prelim_auditd_immutable_check.rc not in [ 0, 1, 2 ] + register: prelim_auditd_immutable_check + - name: "PRELIM | PATCH | Configure System Accounting (auditd)" when: - '"auditd" not in ansible_facts.packages' diff --git a/tasks/section_1/cis_1.1.2.3.x.yml b/tasks/section_1/cis_1.1.2.3.x.yml index efb1dc3..7c362b6 100644 --- a/tasks/section_1/cis_1.1.2.3.x.yml +++ b/tasks/section_1/cis_1.1.2.3.x.yml @@ -1,12 +1,12 @@ --- -- name: "1.1.2.3.1 | PATCH | Ensure /home is a separate partition" +- name: "1.1.2.3.1 | PATCH | Ensure separate partition exists for /home" when: - rhel9cis_rule_1_1_2_3_1 - required_mount not in prelim_mount_names tags: - - level1-server - - level1-workstation + - level2-server + - level2-workstation - audit - mounts - rule_1.1.2.3.1 diff --git a/tasks/section_1/cis_1.1.2.4.x.yml b/tasks/section_1/cis_1.1.2.4.x.yml index f89fe3f..6534ec2 100644 --- a/tasks/section_1/cis_1.1.2.4.x.yml +++ b/tasks/section_1/cis_1.1.2.4.x.yml @@ -1,12 +1,12 @@ --- -- name: "1.1.2.4.1 | PATCH | Ensure /var is a separate partition" +- name: "1.1.2.4.1 | PATCH | Ensure separate partition exists for /var" when: - rhel9cis_rule_1_1_2_4_1 - required_mount not in prelim_mount_names tags: - - level1-server - - level1-workstation + - level2-server + - level2-workstation - audit - mounts - rule_1.1.2.4.1 diff --git a/tasks/section_1/cis_1.1.2.5.x.yml b/tasks/section_1/cis_1.1.2.5.x.yml index 180d016..ae76bce 100644 --- a/tasks/section_1/cis_1.1.2.5.x.yml +++ b/tasks/section_1/cis_1.1.2.5.x.yml @@ -1,12 +1,12 @@ --- -- name: "1.1.2.5.1 | PATCH | Ensure /var/tmp is a separate partition" +- name: "1.1.2.5.1 | PATCH | Ensure separate partition exists for /var/tmp" when: - rhel9cis_rule_1_1_2_5_1 - required_mount not in prelim_mount_names tags: - - level1-server - - level1-workstation + - level2-server + - level2-workstation - audit - mounts - rule_1.1.2.5.1 diff --git a/tasks/section_1/cis_1.1.2.6.x.yml b/tasks/section_1/cis_1.1.2.6.x.yml index b27e4cc..9d3e5a3 100644 --- a/tasks/section_1/cis_1.1.2.6.x.yml +++ b/tasks/section_1/cis_1.1.2.6.x.yml @@ -1,12 +1,12 @@ --- -- name: "1.1.2.6.1 | PATCH | Ensure /var/log is a separate partition" +- name: "1.1.2.6.1 | PATCH | Ensure separate partition exists for /var/log" when: - rhel9cis_rule_1_1_2_6_1 - required_mount not in prelim_mount_names tags: - - level1-server - - level1-workstation + - level2-server + - level2-workstation - audit - mounts - rule_1.1.2.6.1 diff --git a/tasks/section_1/cis_1.1.2.7.x.yml b/tasks/section_1/cis_1.1.2.7.x.yml index b4513dd..e658041 100644 --- a/tasks/section_1/cis_1.1.2.7.x.yml +++ b/tasks/section_1/cis_1.1.2.7.x.yml @@ -1,12 +1,12 @@ --- -- name: "1.1.2.7.1 | PATCH | Ensure /var/log/audit is a separate partition" +- name: "1.1.2.7.1 | PATCH | Ensure separate partition exists for /var/log/audit" when: - rhel9cis_rule_1_1_2_7_1 - required_mount not in prelim_mount_names tags: - - level1-server - - level1-workstation + - level2-server + - level2-workstation - audit - mounts - rule_1.1.2.7.1 diff --git a/tasks/section_1/cis_1.3.1.x.yml b/tasks/section_1/cis_1.3.1.x.yml index ad7d844..5591648 100644 --- a/tasks/section_1/cis_1.3.1.x.yml +++ b/tasks/section_1/cis_1.3.1.x.yml @@ -55,7 +55,7 @@ policy: "{{ rhel9cis_selinux_pol }}" state: "{{ rhel9cis_selinux_enforce }}" -- name: "1.3.1.4 | PATCH | Ensure the SELinux state is not disabled" +- name: "1.3.1.4 | PATCH | Ensure the SELinux mode is not disabled" when: - rhel9cis_rule_1_3_1_4 - not rhel9cis_selinux_disable @@ -72,7 +72,7 @@ policy: "{{ rhel9cis_selinux_pol }}" state: "{{ rhel9cis_selinux_enforce }}" -- name: "1.3.1.5 | PATCH | Ensure the SELinux state is enforcing" +- name: "1.3.1.5 | PATCH | Ensure the SELinux mode is enforcing" when: - rhel9cis_selinux_enforce == 'enforcing' - rhel9cis_rule_1_3_1_5 diff --git a/tasks/section_1/cis_1.5.x.yml b/tasks/section_1/cis_1.5.x.yml index 992785b..0b7101f 100644 --- a/tasks/section_1/cis_1.5.x.yml +++ b/tasks/section_1/cis_1.5.x.yml @@ -1,6 +1,6 @@ --- -- name: "1.5.1 | PATCH | Ensure address space layout randomization (ASLR) is enabled" +- name: "1.5.1 | PATCH | Ensure address space layout randomization is enabled" when: rhel9cis_rule_1_5_1 tags: - level1-server @@ -11,11 +11,11 @@ - NIST800-53R5_CM-6 - NIST800-53R5_CM-6.1 block: - - name: "1.5.1 | PATCH | Ensure address space layout randomization (ASLR) is enabled" + - name: "1.5.1 | PATCH | Ensure address space layout randomization is enabled" ansible.builtin.set_fact: rhel9cis_sysctl_update: true - - name: "1.5.1 | PATCH | Ensure address space layout randomization (ASLR) is enabled" + - name: "1.5.1 | PATCH | Ensure address space layout randomization is enabled" ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-kernel_sysctl.conf" diff --git a/tasks/section_1/cis_1.6.x.yml b/tasks/section_1/cis_1.6.x.yml index 8aace04..d81b578 100644 --- a/tasks/section_1/cis_1.6.x.yml +++ b/tasks/section_1/cis_1.6.x.yml @@ -130,7 +130,7 @@ - Update Crypto Policy - Set Crypto Policy -- name: "1.6.6 | PATCH | Ensure system wide crypto policy disables chacha20-poly1305 for ssh" +- name: "1.6.6 | PATCH | Ensure system wide crypto policy disables chacha20- poly1305 for ssh" when: - rhel9cis_rule_1_6_6 - "'NO-SSHWEAKCIPHERS' not in rhel9cis_crypto_policy_module" @@ -144,7 +144,7 @@ - rule_1.6.6 - NIST800-53R5_SC-6 block: - - name: "1.6.6 | PATCH | Ensure system wide crypto policy disables chacha20-poly1305 for ssh | Add submodule exclusion" + - name: "1.6.6 | PATCH | Ensure system wide crypto policy disables chacha20- poly1305 for ssh | Add submodule exclusion" ansible.builtin.template: src: etc/crypto-policies/policies/modules/NO-SSHWEAKCIPHERS.pmod.j2 dest: /etc/crypto-policies/policies/modules/NO-SSHWEAKCIPHERS.pmod @@ -153,7 +153,7 @@ mode: 'g-wx,o-rwx' register: discovered_no_sshweakciphers_template - - name: "1.6.6 | PATCH | Ensure system wide crypto policy disables chacha20-poly1305 for ssh | submodule to crypto policy modules" + - name: "1.6.6 | PATCH | Ensure system wide crypto policy disables chacha20- poly1305 for ssh | submodule to crypto policy modules" ansible.builtin.set_fact: rhel9cis_crypto_policy_module: "{{ rhel9cis_crypto_policy_module + ':' + 'NO-SSHWEAKCIPHERS' }}" changed_when: discovered_no_sshweakciphers_template is changed # noqa: no-handler diff --git a/tasks/section_1/cis_1.7.x.yml b/tasks/section_1/cis_1.7.x.yml index 7f45476..a52e07d 100644 --- a/tasks/section_1/cis_1.7.x.yml +++ b/tasks/section_1/cis_1.7.x.yml @@ -53,7 +53,7 @@ group: root mode: 'go-wx' -- name: "1.7.4 | PATCH | Ensure permissions on /etc/motd are configured" +- name: "1.7.4 | PATCH | Ensure access to /etc/motd is configured" when: rhel9cis_rule_1_7_4 tags: - level1-server @@ -69,7 +69,7 @@ group: root mode: 'go-wx' -- name: "1.7.5 | PATCH | Ensure permissions on /etc/issue are configured" +- name: "1.7.5 | PATCH | Ensure access to /etc/issue is configured" when: rhel9cis_rule_1_7_5 tags: - level1-server @@ -85,7 +85,7 @@ group: root mode: 'go-wx' -- name: "1.7.6 | PATCH | Ensure permissions on /etc/issue.net are configured" +- name: "1.7.6 | PATCH | Ensure access to /etc/issue.net is configured" when: rhel9cis_rule_1_7_6 tags: - level1-server diff --git a/tasks/section_1/cis_1.8.x.yml b/tasks/section_1/cis_1.8.x.yml index c6f91b3..96137b3 100644 --- a/tasks/section_1/cis_1.8.x.yml +++ b/tasks/section_1/cis_1.8.x.yml @@ -198,7 +198,7 @@ - rhel9cis_gui tags: - level1-server - - level2-workstation + - level1-workstation - patch - gui - rule_1.8.8 @@ -226,7 +226,7 @@ - rhel9cis_gui tags: - level1-server - - level2-workstation + - level1-workstation - patch - gui - rule_1.8.9 diff --git a/tasks/section_2/cis_2.2.x.yml b/tasks/section_2/cis_2.2.x.yml index 0e019e7..2729114 100644 --- a/tasks/section_2/cis_2.2.x.yml +++ b/tasks/section_2/cis_2.2.x.yml @@ -64,7 +64,7 @@ name: telnet state: absent -- name: "2.2.5 | PATCH | Ensure TFTP client is not installed" +- name: "2.2.5 | PATCH | Ensure tftp client is not installed" when: - not rhel9cis_tftp_client - rhel9cis_rule_2_2_5 diff --git a/tasks/section_2/cis_2.4.x.yml b/tasks/section_2/cis_2.4.x.yml index c4b6b8b..d08dfce 100644 --- a/tasks/section_2/cis_2.4.x.yml +++ b/tasks/section_2/cis_2.4.x.yml @@ -1,6 +1,6 @@ --- -- name: "2.4.1.1 | PATCH | Ensure cron daemon is enabled" +- name: "2.4.1.1 | PATCH | Ensure cron daemon is enabled and active" when: rhel9cis_rule_2_4_1_1 tags: - level1-server diff --git a/tasks/section_3/cis_3.3.x.yml b/tasks/section_3/cis_3.3.x.yml index 0281f12..26ff980 100644 --- a/tasks/section_3/cis_3.3.x.yml +++ b/tasks/section_3/cis_3.3.x.yml @@ -1,6 +1,6 @@ --- -- name: "3.3.1 | PATCH | Ensure IP forwarding is disabled" +- name: "3.3.1 | PATCH | Ensure ip forwarding is disabled" when: - not rhel9cis_is_router - rhel9cis_rule_3_3_1 @@ -16,23 +16,23 @@ - NIST800-53R5_CM-7 - NIST800-53R5_IA-5 block: - - name: "3.3.1 | PATCH | Ensure IP forwarding is disabled | Disable IPv4 forwarding | Set Fact" + - name: "3.3.1 | PATCH | Ensure ip forwarding is disabled | Disable IPv4 forwarding | Set Fact" ansible.builtin.set_fact: rhel9cis_sysctl_update: true rhel9cis_flush_ipv4_route: true - - name: "3.3.1 | PATCH | Ensure IP forwarding is disabled | Disable IPv4 forwarding" + - name: "3.3.1 | PATCH | Ensure ip forwarding is disabled | Disable IPv4 forwarding" ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" - - name: "3.3.1 | PATCH | Ensure IP forwarding is disabled | IPv6" + - name: "3.3.1 | PATCH | Ensure ip forwarding is disabled | IPv6" when: rhel9cis_ipv6_required block: - - name: "3.3.1 | PATCH | Ensure IP forwarding is disabled | Disable IPv6 forwarding | Set Fact" + - name: "3.3.1 | PATCH | Ensure ip forwarding is disabled | Disable IPv6 forwarding | Set Fact" ansible.builtin.set_fact: rhel9cis_flush_ipv6_route: true - - name: "3.3.1 | PATCH | Ensure IP forwarding is disabled | Disable IPv6 forwarding" + - name: "3.3.1 | PATCH | Ensure ip forwarding is disabled | Disable IPv6 forwarding" ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl.conf" @@ -60,7 +60,7 @@ ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" -- name: "3.3.3 | PATCH | Ensure bogus ICMP responses are ignored" +- name: "3.3.3 | PATCH | Ensure bogus icmp responses are ignored" when: rhel9cis_rule_3_3_3 tags: - level1-server @@ -74,16 +74,16 @@ - NIST800-53R5_CM-7 - NIST800-53R5_IA-5 block: - - name: "3.3.3 | PATCH | Ensure bogus ICMP responses are ignored | Set Fact" + - name: "3.3.3 | PATCH | Ensure bogus icmp responses are ignored | Set Fact" ansible.builtin.set_fact: rhel9cis_sysctl_update: true rhel9cis_flush_ipv4_route: true - - name: "3.3.3 | PATCH | Ensure bogus ICMP responses are ignored" + - name: "3.3.3 | PATCH | Ensure bogus icmp responses are ignored" ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" -- name: "3.3.4 | PATCH | Ensure broadcast ICMP requests are ignored" +- name: "3.3.4 | PATCH | Ensure broadcast icmp requests are ignored" when: rhel9cis_rule_3_3_4 tags: - level1-server @@ -97,7 +97,7 @@ - NIST800-53R5_CM-7 - NIST800-53R5_IA-5 block: - - name: "3.3.4 | PATCH | Ensure broadcast ICMP requests are ignored | Set Fact" + - name: "3.3.4 | PATCH | Ensure broadcast icmp requests are ignored | Set Fact" ansible.builtin.set_fact: rhel9cis_sysctl_update: true rhel9cis_flush_ipv4_route: true @@ -106,7 +106,7 @@ ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" -- name: "3.3.5 | PATCH | Ensure ICMP redirects are not accepted" +- name: "3.3.5 | PATCH | Ensure icmp redirects are not accepted" when: rhel9cis_rule_3_3_5 tags: - level1-server @@ -120,27 +120,27 @@ - NIST800-53R5_CM-7 - NIST800-53R5_IA-5 block: - - name: "3.3.5 | PATCH | Ensure ICMP redirects are not accepted | Set Fact" + - name: "3.3.5 | PATCH | Ensure icmp redirects are not accepted | Set Fact" ansible.builtin.set_fact: rhel9cis_sysctl_update: true rhel9cis_flush_ipv4_route: true - - name: "3.3.5 | PATCH | Ensure ICMP redirects are not accepted" + - name: "3.3.5 | PATCH | Ensure icmp redirects are not accepted" ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" - - name: "3.3.5 | PATCH | Ensure ICMP redirects are not accepted | IPv6" + - name: "3.3.5 | PATCH | Ensure icmp redirects are not accepted | IPv6" when: rhel9cis_ipv6_required block: - - name: "3.3.5 | PATCH | Ensure ICMP redirects are not accepted | IPv6 | Set Fact" + - name: "3.3.5 | PATCH | Ensure icmp redirects are not accepted | IPv6 | Set Fact" ansible.builtin.set_fact: rhel9cis_flush_ipv6_route: true - - name: "3.3.5 | PATCH | Ensure ICMP redirects are not accepted | IPv6" + - name: "3.3.5 | PATCH | Ensure icmp redirects are not accepted | IPv6" ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl.conf" -- name: "3.3.6 | PATCH | Ensure secure ICMP redirects are not accepted" +- name: "3.3.6 | PATCH | Ensure secure icmp redirects are not accepted" when: rhel9cis_rule_3_3_6 tags: - level1-server @@ -154,27 +154,27 @@ - NIST800-53R5_CM-7 - NIST800-53R5_IA-5 block: - - name: "3.3.6 | PATCH | Ensure secure ICMP redirects are not accepted | IPv4 | Set Fact" + - name: "3.3.6 | PATCH | Ensure secure icmp redirects are not accepted | IPv4 | Set Fact" ansible.builtin.set_fact: rhel9cis_sysctl_update: true rhel9cis_flush_ipv4_route: true - - name: "3.3.6 | PATCH | Ensure secure ICMP redirects are not accepted | IPv4" + - name: "3.3.6 | PATCH | Ensure secure icmp redirects are not accepted | IPv4" ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" - - name: "3.3.6 | PATCH | Ensure secure ICMP redirects are not accepted | IPv6" + - name: "3.3.6 | PATCH | Ensure secure icmp redirects are not accepted | IPv6" when: rhel9cis_ipv6_required block: - - name: "3.3.6 | PATCH | Ensure secure ICMP redirects are not accepted | IPv6 | Set Fact" + - name: "3.3.6 | PATCH | Ensure secure icmp redirects are not accepted | IPv6 | Set Fact" ansible.builtin.set_fact: rhel9cis_flush_ipv6_route: true - - name: "3.3.6 | PATCH | Ensure secure ICMP redirects are not accepted | IPv6" + - name: "3.3.6 | PATCH | Ensure secure icmp redirects are not accepted | IPv6" ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl.conf" -- name: "3.3.7 | PATCH | Ensure Reverse Path Filtering is enabled" +- name: "3.3.7 | PATCH | Ensure reverse path filtering is enabled" when: rhel9cis_rule_3_3_7 tags: - level1-server @@ -188,12 +188,12 @@ - NIST800-53R5_CM-7 - NIST800-53R5_IA-5 block: - - name: "3.3.7 | PATCH | Ensure Reverse Path Filtering is enabled | Set Fact" + - name: "3.3.7 | PATCH | Ensure reverse path filtering is enabled | Set Fact" ansible.builtin.set_fact: rhel9cis_sysctl_update: true rhel9cis_flush_ipv4_route: true - - name: "3.3.7 | PATCH | Ensure Reverse Path Filtering is enabled" + - name: "3.3.7 | PATCH | Ensure reverse path filtering is enabled" ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" @@ -249,7 +249,7 @@ ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" -- name: "3.3.10 | PATCH | Ensure TCP SYN Cookies is enabled" +- name: "3.3.10 | PATCH | Ensure tcp syn cookies is enabled" when: rhel9cis_rule_3_3_10 tags: - level1-server @@ -263,22 +263,22 @@ - NIST800-53R5_CM-7 - NIST800-53R5_IA-5 block: - - name: "3.3.10 | PATCH | Ensure TCP SYN Cookies is enabled | Set Fact" + - name: "3.3.10 | PATCH | Ensure tcp syn cookies is enabled | Set Fact" ansible.builtin.set_fact: rhel9cis_sysctl_update: true rhel9cis_flush_ipv4_route: true - - name: "3.3.10 | PATCH | Ensure TCP SYN Cookies is enabled" + - name: "3.3.10 | PATCH | Ensure tcp syn cookies is enabled" ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" -- name: "3.3.11 | PATCH | Ensure IPv6 router advertisements are not accepted" +- name: "3.3.11 | PATCH | Ensure ipv6 router advertisements are not accepted" when: - rhel9cis_ipv6_required - rhel9cis_rule_3_3_11 tags: - - level2-server - - level2-workstation + - level1-server + - level1-workstation - sysctl - patch - rule_3.3.11 @@ -288,11 +288,11 @@ - NIST800-53R5_CM-7 - NIST800-53R5_IA-5 block: - - name: "3.3.11 | PATCH | Ensure IPv6 router advertisements are not accepted | IPv6 | Set Fact" + - name: "3.3.11 | PATCH | Ensure ipv6 router advertisements are not accepted | IPv6 | Set Fact" ansible.builtin.set_fact: rhel9cis_sysctl_update: true rhel9cis_flush_ipv6_route: true - - name: "3.3.11 | PATCH | Ensure IPv6 router advertisements are not accepted | IPv6" + - name: "3.3.11 | PATCH | Ensure ipv6 router advertisements are not accepted | IPv6" ansible.builtin.debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl" diff --git a/tasks/section_5/cis_5.1.x.yml b/tasks/section_5/cis_5.1.x.yml index a75e444..78c671a 100644 --- a/tasks/section_5/cis_5.1.x.yml +++ b/tasks/section_5/cis_5.1.x.yml @@ -134,7 +134,7 @@ ansible.builtin.set_fact: rhel9cis_crypto_policy_module: "{{ rhel9cis_crypto_policy_module + ':NO-SHA1' }}" -- name: "5.1.6 | PATCH | Ensure sshd KexAlgorithms is configured" +- name: "5.1.6 | PATCH | Ensure sshd MACs are configured" when: - rhel9cis_rule_5_1_6 - "'NO-SSHWEAKMACS' not in rhel9cis_crypto_policy_module" @@ -148,7 +148,7 @@ - rule_5.1.6 - NIST800-53R5_SC-6 block: - - name: "5.1.6 | PATCH | Ensure sshd KexAlgorithms is configured | Add submodule exclusion" + - name: "5.1.6 | PATCH | Ensure sshd MACs are configured | Add submodule exclusion" ansible.builtin.template: src: etc/crypto-policies/policies/modules/NO-SSHWEAKMACS.pmod.j2 dest: /etc/crypto-policies/policies/modules/NO-SSHWEAKMACS.pmod @@ -159,7 +159,7 @@ - Update Crypto Policy - Set Crypto Policy - - name: "5.1.6 | PATCH | Ensure sshd KexAlgorithms is configured | submodule to crypto policy modules" + - name: "5.1.6 | PATCH | Ensure sshd MACs are configured | submodule to crypto policy modules" ansible.builtin.set_fact: rhel9cis_crypto_policy_module: "{{ rhel9cis_crypto_policy_module + ':' + 'NO-SSHWEAKMACS' }}" @@ -290,7 +290,7 @@ - name: "5.1.11 | PATCH | Ensure sshd GSSAPIAuthentication is disabled" when: rhel9cis_rule_5_1_11 tags: - - level1-server + - level2-server - level1-workstation - patch - sshd @@ -360,7 +360,7 @@ validate: sshd -t -f %s notify: Restart sshd -- name: "5.1.14 | PATCH | Ensure sshd LoginGraceTime is set to one minute or less" +- name: "5.1.14 | PATCH | Ensure sshd LoginGraceTime is configured" when: rhel9cis_rule_5_1_14 tags: - level1-server @@ -378,7 +378,7 @@ validate: sshd -t -f %s notify: Restart sshd -- name: "5.1.15 | PATCH | Ensure sshd LogLevel is appropriate" +- name: "5.1.15 | PATCH | Ensure sshd LogLevel is configured" when: rhel9cis_rule_5_1_15 tags: - level1-server @@ -398,7 +398,7 @@ validate: sshd -t -f %s notify: Restart sshd -- name: "5.1.16 | PATCH | Ensure sshd MaxAuthTries is set to 4 or less" +- name: "5.1.16 | PATCH | Ensure sshd MaxAuthTries is configured" when: rhel9cis_rule_5_1_16 tags: - level1-server @@ -438,7 +438,7 @@ validate: sshd -t -f %s notify: Restart sshd -- name: "5.1.18 | PATCH | Ensure SSH MaxSessions is set to 10 or less" +- name: "5.1.18 | PATCH | Ensure sshd MaxSessions is configured" when: rhel9cis_rule_5_1_18 tags: - level1-server @@ -522,7 +522,7 @@ validate: sshd -t -f %s notify: Restart sshd -- name: "5.1.22 | PATCH | Ensure SSH PAM is enabled" +- name: "5.1.22 | PATCH | Ensure sshd UsePAM is enabled" when: rhel9cis_rule_5_1_22 tags: - level1-server diff --git a/tasks/section_5/cis_5.3.1.x.yml b/tasks/section_5/cis_5.3.1.x.yml index ce5ae8a..7ce6344 100644 --- a/tasks/section_5/cis_5.3.1.x.yml +++ b/tasks/section_5/cis_5.3.1.x.yml @@ -39,7 +39,7 @@ ansible.builtin.set_fact: authselect_update: OK -- name: "5.3.1.3 | PATCH | Ensure libpwquality is installed" +- name: "5.3.1.3 | PATCH | Ensure latest version of libpwquality is installed" when: - rhel9cis_rule_5_3_1_3 - ansible_facts.packages['libpwquality'][0]['version'] is version('1.4.4-8', '<') or diff --git a/tasks/section_5/cis_5.3.2.x.yml b/tasks/section_5/cis_5.3.2.x.yml index 51f032e..143e51f 100644 --- a/tasks/section_5/cis_5.3.2.x.yml +++ b/tasks/section_5/cis_5.3.2.x.yml @@ -65,7 +65,7 @@ failed_when: discovered_authselect_current_faillock.rc not in [ 0, 1 ] register: discovered_authselect_current_faillock - - name: "5.3.2.2 | PATCH | Ensure pam_faillock module is enabled | Add feature if missing authselect" # noqa syntax-check[specific]" + - name: '5.3.2.2 | PATCH | Ensure pam_faillock module is enabled | Add feature if missing authselect" # noqa syntax-check[specific]' when: - rhel9cis_allow_authselect_updates - discovered_authselect_current_faillock.rc != 0 diff --git a/tasks/section_5/cis_5.3.3.1.x.yml b/tasks/section_5/cis_5.3.3.1.x.yml index 0aadbe3..3efdc2d 100644 --- a/tasks/section_5/cis_5.3.3.1.x.yml +++ b/tasks/section_5/cis_5.3.3.1.x.yml @@ -87,8 +87,8 @@ - name: "5.3.3.1.3 | PATCH | Ensure password failed attempts lockout includes root account" when: rhel9cis_rule_5_3_3_1_3 tags: - - level1-server - - level1-workstation + - level2-server + - level2-workstation - automated - patch - pam diff --git a/tasks/section_5/cis_5.3.3.2.x.yml b/tasks/section_5/cis_5.3.3.2.x.yml index a53d857..9914b71 100644 --- a/tasks/section_5/cis_5.3.3.2.x.yml +++ b/tasks/section_5/cis_5.3.3.2.x.yml @@ -67,7 +67,7 @@ - NIST800-53R5_IA-5 - pam block: - - name: "5.3.3.2.2 | PATCH | Ensure minimum password length is configured | Remove minlen from conf files except expected file" + - name: "5.3.3.2.2 | PATCH | Ensure password length is configured | Remove minlen from conf files except expected file" when: - item != rhel9cis_passwd_minlen_file - rhel9cis_disruption_high @@ -81,7 +81,7 @@ - /etc/pam.d/password-auth - "{{ prelim_pam_pwquality_confs.files | default([]) }}" - - name: "5.3.3.2.2 | PATCH | Ensure minimum password length is configured | Ensure minlen file exists" + - name: "5.3.3.2.2 | PATCH | Ensure password length is configured | Ensure minlen file exists" ansible.builtin.template: src: "{{ rhel9cis_passwd_minlen_file }}.j2" dest: "/{{ rhel9cis_passwd_minlen_file }}" @@ -89,7 +89,7 @@ group: root mode: 'go-rwx' - - name: "5.3.3.2.2 | PATCH | Ensure minimum password length is configured | Remove minlen from pam files NOT AuthSelect" + - name: "5.3.3.2.2 | PATCH | Ensure password length is configured | Remove minlen from pam files NOT AuthSelect" when: - not rhel9cis_allow_authselect_updates - rhel9cis_disruption_high @@ -101,7 +101,7 @@ - password - system - - name: "5.3.3.2.2 | PATCH | Ensure minimum password length is configured | Remove minlen from pam files AuthSelect" + - name: "5.3.3.2.2 | PATCH | Ensure password length is configured | Remove minlen from pam files AuthSelect" when: - rhel9cis_allow_authselect_updates - rhel9cis_disruption_high @@ -226,7 +226,7 @@ - system notify: Authselect update -- name: "5.3.3.2.5 | PATCH | Ensure password maximum sequential characters is is configured" +- name: "5.3.3.2.5 | PATCH | Ensure password maximum sequential characters is configured" when: rhel9cis_rule_5_3_3_2_5 tags: - level1-server diff --git a/tasks/section_5/cis_5.3.3.3.x.yml b/tasks/section_5/cis_5.3.3.3.x.yml index 9daf71a..3f753bb 100644 --- a/tasks/section_5/cis_5.3.3.3.x.yml +++ b/tasks/section_5/cis_5.3.3.3.x.yml @@ -15,13 +15,13 @@ failed_when: discovered_pwhistory_remember.rc not in [0, 1] register: discovered_pwhistory_remember - - name: "5.3.3.3.1 | PATCH | Ensure password number of changed characters is configured | Ensure remember is set pwhistory file" + - name: "5.3.3.3.1 | PATCH | Ensure password history remember is configured | Ensure remember is set pwhistory file" ansible.builtin.lineinfile: path: "/etc/security/pwhistory.conf" regexp: remember\s*=\s*\d* line: remember = {{ rhel9cis_pamd_pwhistory_remember }} - - name: "5.3.3.3.1 | PATCH | Ensure password number of changed characters is configured | Remove remember from pam files NOT AuthSelect" + - name: "5.3.3.3.1 | PATCH | Ensure password history remember is configured | Remove remember from pam files NOT AuthSelect" when: - not rhel9cis_allow_authselect_updates - rhel9cis_disruption_high @@ -33,7 +33,7 @@ - password - system - - name: "5.3.3.3.1 | PATCH | Ensure password number of changed characters is configured | Remove remember from pam files AuthSelect" + - name: "5.3.3.3.1 | PATCH | Ensure password history remember is configured | Remove remember from pam files AuthSelect" when: - rhel9cis_allow_authselect_updates - rhel9cis_disruption_high diff --git a/tasks/section_5/cis_5.3.3.4.x.yml b/tasks/section_5/cis_5.3.3.4.x.yml index ddca97a..4ce08f1 100644 --- a/tasks/section_5/cis_5.3.3.4.x.yml +++ b/tasks/section_5/cis_5.3.3.4.x.yml @@ -27,7 +27,7 @@ replace: '' loop: "{{ discovered_pam_nullok.stdout_lines }}" - - name: "5.3.3.4.1 | PATCH | Ensure password number of changed characters is configured | Remove nullok from pam files AuthSelect" + - name: "5.3.3.4.1 | PATCH | Ensure pam_unix does not include nullok | Remove nullok from pam files AuthSelect" when: rhel9cis_allow_authselect_updates ansible.builtin.replace: path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" @@ -65,7 +65,7 @@ replace: '' loop: "{{ discovered_pam_remember.stdout_lines }}" - - name: "5.3.3.4.2 | PATCH | Ensure pam_unix does not include remember | Remove remember from pam files AuthSelect" + - name: "5.3.3.4.2 | PATCH | Ensure pam_unix does not include remember | Remove remember from pam files AuthSelect" when: rhel9cis_allow_authselect_updates ansible.builtin.replace: path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" diff --git a/tasks/section_5/cis_5.4.1.x.yml b/tasks/section_5/cis_5.4.1.x.yml index badca42..061e736 100644 --- a/tasks/section_5/cis_5.4.1.x.yml +++ b/tasks/section_5/cis_5.4.1.x.yml @@ -1,6 +1,6 @@ --- -- name: "5.4.1.1 | PATCH | Ensure password expiration is 365 days or less" +- name: "5.4.1.1 | PATCH | Ensure password expiration is configured" when: rhel9cis_rule_5_4_1_1 tags: - level1-server @@ -14,7 +14,7 @@ - NIST800-53R5_CM-7 - NIST800-53R5_IA-5 block: - - name: "5.4.1.1 | PATCH | Ensure password expiration is 365 days or less" + - name: "5.4.1.1 | PATCH | Ensure password expiration is configured" ansible.builtin.lineinfile: path: /etc/login.defs regexp: '^PASS_MAX_DAYS' @@ -27,7 +27,7 @@ check_mode: false register: discovered_max_days - - name: "5.4.1.1 | PATCH | Ensure password expiration is 365 days or less | Set existing users PASS_MAX_DAYS" + - name: "5.4.1.1 | PATCH | Ensure password expiration is configured | Set existing users PASS_MAX_DAYS" when: - discovered_max_days.stdout_lines | length > 0 - item in prelim_interactive_users | map(attribute='username') | list @@ -40,8 +40,8 @@ - name: "5.4.1.2 | PATCH | Ensure minimum password days is configured" when: rhel9cis_rule_5_4_1_2 tags: - - level1-server - - level1-workstation + - level2-server + - level2-workstation - patch - password - rule_5.4.1.2 @@ -140,7 +140,7 @@ check_mode: false register: discovered_passwdlck_user_list - - name: "5.4.1.5 | PATCH | Ensure inactive password lock is 30 days or less | Apply Inactive setting to existing accounts" + - name: "5.4.1.5 | PATCH | Ensure inactive password lock is configured | Apply Inactive setting to existing accounts" when: item in prelim_interactive_users | map(attribute='username') | list ansible.builtin.command: chage --inactive {{ rhel9cis_inactivelock.lock_days }} "{{ item }}" changed_when: true diff --git a/tasks/section_5/cis_5.4.2.x.yml b/tasks/section_5/cis_5.4.2.x.yml index d1ba865..bf8cab2 100644 --- a/tasks/section_5/cis_5.4.2.x.yml +++ b/tasks/section_5/cis_5.4.2.x.yml @@ -94,7 +94,7 @@ vars: warn_control_id: '5.4.2.3' -- name: "5.4.2.4 | PATCH | Ensure root account access is controlled " +- name: "5.4.2.4 | PATCH | Ensure root account access is controlled" when: rhel9cis_rule_5_4_2_4 tags: - level1-server @@ -105,7 +105,7 @@ ansible.builtin.debug: msg: "This is set as an assert in tasks/main" -- name: "5.4.2.5 | PATCH | Ensure root PATH Integrity" +- name: "5.4.2.5 | PATCH | Ensure root path integrity" when: rhel9cis_rule_5_4_2_5 tags: - level1-server diff --git a/tasks/section_6/cis_6.2.2.x.yml b/tasks/section_6/cis_6.2.2.x.yml index 82302ed..30c1006 100644 --- a/tasks/section_6/cis_6.2.2.x.yml +++ b/tasks/section_6/cis_6.2.2.x.yml @@ -4,7 +4,7 @@ when: rhel9cis_rule_6_2_2_2 tags: - level1-server - - level2-workstation + - level1-workstation - patch - journald - rule_6.2.2.2 diff --git a/tasks/section_6/cis_6.2.3.x.yml b/tasks/section_6/cis_6.2.3.x.yml index 42c7725..56c28fa 100644 --- a/tasks/section_6/cis_6.2.3.x.yml +++ b/tasks/section_6/cis_6.2.3.x.yml @@ -1,6 +1,6 @@ --- -- name: "6.2.3.1 | PATCH | Ensure rsyslog installed" +- name: "6.2.3.1 | PATCH | Ensure rsyslog is installed" when: - "'rsyslog' not in ansible_facts.packages" - rhel9cis_rule_6_2_3_1 @@ -17,7 +17,7 @@ name: rsyslog state: present -- name: "6.2.3.2 | PATCH | Ensure rsyslog Service is enabled and active" +- name: "6.2.3.2 | PATCH | Ensure rsyslog service is enabled and active" when: rhel9cis_rule_6_2_3_2 tags: - level1-server @@ -68,7 +68,7 @@ line: '$FileCreateMode 0640' notify: Restart rsyslog -- name: "6.2.3.5 | PATCH | Ensure logging is configured" +- name: "6.2.3.5 | PATCH | Ensure rsyslog logging is configured" when: rhel9cis_rule_6_2_3_5 tags: - level1-server @@ -93,7 +93,7 @@ - "These are the current logging configurations for rsyslog, please review:" - "{{ discovered_configured_rsyslog.stdout_lines }}" - - name: "6.2.3.5 | PATCH | Ensure logging is configured | mail.* log setting" + - name: "6.2.3.5 | PATCH | Ensure rsyslog logging is configured | mail.* log setting" when: rhel9cis_rsyslog_ansiblemanaged ansible.builtin.blockinfile: path: /etc/rsyslog.conf @@ -107,7 +107,7 @@ insertafter: '# Log all the mail messages in one place.' notify: Restart rsyslog - - name: "6.2.3.5 | PATCH | Ensure logging is configured | news.crit log setting" + - name: "6.2.3.5 | PATCH | Ensure rsyslog logging is configured | news.crit log setting" when: rhel9cis_rsyslog_ansiblemanaged ansible.builtin.blockinfile: path: /etc/rsyslog.conf @@ -120,7 +120,7 @@ insertafter: '# Save news errors of level crit and higher in a special file.' notify: Restart rsyslog - - name: "6.2.3.5 | PATCH | Ensure logging is configured | Misc. log setting" + - name: "6.2.3.5 | PATCH | Ensure rsyslog logging is configured | Misc. log setting" when: rhel9cis_rsyslog_ansiblemanaged ansible.builtin.blockinfile: path: /etc/rsyslog.conf @@ -134,7 +134,7 @@ insertbefore: '# ### sample forwarding rule ###' notify: Restart rsyslog - - name: "6.2.3.5 | PATCH | Ensure logging is configured | Local log settings" + - name: "6.2.3.5 | PATCH | Ensure rsyslog logging is configured | Local log settings" ansible.builtin.blockinfile: path: /etc/rsyslog.conf state: present @@ -149,7 +149,7 @@ insertafter: '#### RULES ####' notify: Restart rsyslog - - name: "6.2.3.5 | PATCH | Ensure logging is configured | Auth Settings" + - name: "6.2.3.5 | PATCH | Ensure rsyslog logging is configured | Auth Settings" ansible.builtin.blockinfile: path: /etc/rsyslog.conf state: present @@ -160,7 +160,7 @@ insertafter: '#### RULES ####' notify: Restart rsyslog - - name: "6.2.3.5 | PATCH | Ensure logging is configured | Cron Settings" + - name: "6.2.3.5 | PATCH | Ensure rsyslog logging is configured | Cron Settings" ansible.builtin.blockinfile: path: /etc/rsyslog.conf state: present @@ -208,7 +208,7 @@ - NIST800-53R5_AU-12 - NIST800-53R5_CM-6 block: - - name: "6.2.3.7 | PATCH | Ensure rsyslog is not configured to receive logs from a remote client. | When not log host" + - name: "6.2.3.7 | PATCH | Ensure rsyslog is not configured to receive logs from a remote client | When not log host" when: not rhel9cis_system_is_log_server ansible.builtin.replace: path: /etc/rsyslog.conf @@ -221,7 +221,7 @@ - '^(module\(load="imtcp"\))' - '^(input\(type="imtcp")' - - name: "6.2.3.7 | PATCH | Ensure rsyslog is not configured to receive logs from a remote clients. | When log host" + - name: "6.2.3.7 | PATCH | Ensure rsyslog is not configured to receive logs from a remote client | When log host" when: rhel9cis_system_is_log_server ansible.builtin.replace: path: /etc/rsyslog.conf @@ -254,7 +254,7 @@ state: started enabled: true - - name: "6.2.3.8 | PATCH | Ensure logrotate is configured | set rsyslog conf" + - name: "6.2.3.8 | PATCH | Ensure rsyslog logrotate is configured | set rsyslog conf" ansible.builtin.template: src: etc/logrotate.d/rsyslog_log.j2 dest: /etc/logrotate.d/rsyslog_log diff --git a/tasks/section_6/cis_6.3.1.x.yml b/tasks/section_6/cis_6.3.1.x.yml index e795c83..dc8e7f1 100644 --- a/tasks/section_6/cis_6.3.1.x.yml +++ b/tasks/section_6/cis_6.3.1.x.yml @@ -1,6 +1,6 @@ --- -- name: "6.3.1.1 | PATCH | Ensure auditd is installed" +- name: "6.3.1.1 | PATCH | Ensure auditd packages are installed" when: rhel9cis_rule_6_3_1_1 tags: - level2-server @@ -13,13 +13,13 @@ - NIST800-53R5_AU-12 - NIST800-53R5_SI-5 block: - - name: "6.3.1.1 | PATCH | Ensure auditd is installed | Install auditd packages" + - name: "6.3.1.1 | PATCH | Ensure auditd packages are installed | Install auditd packages" when: '"auditd" not in ansible_facts.packages' ansible.builtin.package: name: audit state: present - - name: "6.3.1.1 | PATCH | Ensure auditd is installed | Install auditd-lib packages" + - name: "6.3.1.1 | PATCH | Ensure auditd packages are installed | Install auditd-lib packages" when: '"auditd-lib" not in ansible_facts.packages' ansible.builtin.package: name: audit-libs diff --git a/tasks/section_6/cis_6.3.3.x.yml b/tasks/section_6/cis_6.3.3.x.yml index 5ff73f9..f42392d 100644 --- a/tasks/section_6/cis_6.3.3.x.yml +++ b/tasks/section_6/cis_6.3.3.x.yml @@ -67,7 +67,7 @@ update_audit_template: true # All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.6 | PATCH | Ensure use of privileged commands is collected" +- name: "6.3.3.6 | PATCH | Ensure use of privileged commands are collected" when: rhel9cis_rule_6_3_3_6 tags: - level2-server @@ -77,14 +77,14 @@ - rule_6.3.3.6 - NIST800-53R5_AU-3 block: - - name: "6.3.3.6 | PATCH | Ensure use of privileged commands is collected" + - name: "6.3.3.6 | PATCH | Ensure use of privileged commands are collected" ansible.builtin.shell: for i in $(df | grep '^/dev' | awk '{ print $NF }'); do find $i -xdev -type f -perm /6000 2>/dev/null; done changed_when: false failed_when: false check_mode: false register: discovered_priv_procs - - name: "6.3.3.6 | PATCH | Ensure use of privileged commands is collected" + - name: "6.3.3.6 | PATCH | Ensure use of privileged commands are collected" ansible.builtin.set_fact: update_audit_template: true notify: update auditd @@ -197,11 +197,11 @@ update_audit_template: true # All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.15 | PATCH | Ensure successful and unsuccessful attempts to use the chcon command are recorded" +- name: "6.3.3.15 | PATCH | Ensure successful and unsuccessful attempts to use the chcon command are collected" when: rhel9cis_rule_6_3_3_15 tags: - level2-server - - level2- workstation + - level2-workstation - patch - auditd - rule_6.3.3.15 @@ -212,7 +212,7 @@ update_audit_template: true # All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.16 | PATCH | Ensure successful and unsuccessful attempts to use the setfacl command are recorded" +- name: "6.3.3.16 | PATCH | Ensure successful and unsuccessful attempts to use the setfacl command are collected" when: rhel9cis_rule_6_3_3_16 tags: - level2-server @@ -227,7 +227,7 @@ update_audit_template: true # All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.17 | PATCH | Ensure successful and unsuccessful attempts to use the chacl command are recorded" +- name: "6.3.3.17 | PATCH | Ensure successful and unsuccessful attempts to use the chacl command are collected" when: rhel9cis_rule_6_3_3_17 tags: - level2-server @@ -242,7 +242,7 @@ update_audit_template: true # All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.18 | PATCH | Ensure successful and unsuccessful attempts to use the usermod command are recorded" +- name: "6.3.3.18 | PATCH | Ensure successful and unsuccessful attempts to use the usermod command are collected" when: rhel9cis_rule_6_3_3_18 tags: - level2-server @@ -257,7 +257,7 @@ update_audit_template: true # All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.19 | PATCH | Ensure kernel module loading and unloading and modification is collected" +- name: "6.3.3.19 | PATCH | Ensure kernel module loading unloading and modification is collected" when: rhel9cis_rule_6_3_3_19 tags: - level2-server @@ -295,9 +295,9 @@ - auditd - rule_6.3.3.21 - NIST800-53R5_AU-3 - ansible.builtin.debug: - msg: - - "Please run augenrules --load if you suspect there is a configuration that is not active" + ansible.builtin.command: augenrules --check + changed_when: false + register: discovered_augenrules_check - name: Auditd | 6.3.3.x | Auditd controls updated when: update_audit_template diff --git a/templates/audit/98_auditd_exception.rules.j2 b/templates/etc/audit/rules.d/98_auditd_exception.rules.j2 similarity index 100% rename from templates/audit/98_auditd_exception.rules.j2 rename to templates/etc/audit/rules.d/98_auditd_exception.rules.j2 diff --git a/templates/audit/99_auditd.rules.j2 b/templates/etc/audit/rules.d/99_auditd.rules.j2 similarity index 100% rename from templates/audit/99_auditd.rules.j2 rename to templates/etc/audit/rules.d/99_auditd.rules.j2 From 53561fbf0805b7dcee8e6389a8c3573c8849db08 Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Wed, 8 Apr 2026 13:51:01 +0100 Subject: [PATCH 07/10] Improved mask logic and package names Signed-off-by: Mark Bolwell --- tasks/section_2/cis_2.1.x.yml | 24 ++++++++++++------------ tasks/section_3/cis_3.1.x.yml | 4 ++-- tasks/section_6/cis_6.2.2.1.x.yml | 4 ++-- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tasks/section_2/cis_2.1.x.yml b/tasks/section_2/cis_2.1.x.yml index 3db8f6d..548ec2b 100644 --- a/tasks/section_2/cis_2.1.x.yml +++ b/tasks/section_2/cis_2.1.x.yml @@ -93,8 +93,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" - state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" + enabled: "{{ ('dhcp-server' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('dhcp-server' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - dhcpd.service @@ -252,8 +252,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" - state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" + enabled: "{{ ('dovecot' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('dovecot' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - "dovecot.socket" @@ -347,8 +347,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" - state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" + enabled: "{{ ('cups' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('cups' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - "cups.socket" @@ -381,8 +381,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" - state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" + enabled: "{{ ('rpcbind' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('rpcbind' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - rpcbind.service @@ -415,8 +415,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" - state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" + enabled: "{{ ('rsync-daemon' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('rsync-daemon' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - 'rsyncd.socket' @@ -509,8 +509,8 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: "{{ item }}" - enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" - state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" + enabled: "{{ ('tftp-server' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('tftp-server' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true loop: - 'tftp.socket' diff --git a/tasks/section_3/cis_3.1.x.yml b/tasks/section_3/cis_3.1.x.yml index b6bff9d..3f4b2df 100644 --- a/tasks/section_3/cis_3.1.x.yml +++ b/tasks/section_3/cis_3.1.x.yml @@ -105,6 +105,6 @@ notify: Systemd daemon reload ansible.builtin.systemd: name: bluetooth.service - enabled: false - state: stopped + enabled: "{{ ('bluez' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('bluez' in ansible_facts.packages) | ternary('stopped', omit) }}" masked: true diff --git a/tasks/section_6/cis_6.2.2.1.x.yml b/tasks/section_6/cis_6.2.2.1.x.yml index aa2415d..dfb8350 100644 --- a/tasks/section_6/cis_6.2.2.1.x.yml +++ b/tasks/section_6/cis_6.2.2.1.x.yml @@ -72,8 +72,8 @@ - NIST800-53R5_AU-12 ansible.builtin.systemd: name: "{{ item }}" - state: stopped - enabled: false + state: "{{ ('systemd-journal-remote' in ansible_facts.packages) | ternary('stopped', omit) }}" + enabled: "{{ ('systemd-journal-remote' in ansible_facts.packages) | ternary(false, omit) }}" masked: true loop: - systemd-journal-remote.socket From 420e036a5694a0e92a5251d111ca5c1f09379503 Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Wed, 8 Apr 2026 13:58:06 +0100 Subject: [PATCH 08/10] updated pkg and mask logic Signed-off-by: Mark Bolwell --- tasks/section_6/cis_6.2.2.1.x.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasks/section_6/cis_6.2.2.1.x.yml b/tasks/section_6/cis_6.2.2.1.x.yml index dfb8350..87dd66e 100644 --- a/tasks/section_6/cis_6.2.2.1.x.yml +++ b/tasks/section_6/cis_6.2.2.1.x.yml @@ -72,8 +72,8 @@ - NIST800-53R5_AU-12 ansible.builtin.systemd: name: "{{ item }}" - state: "{{ ('systemd-journal-remote' in ansible_facts.packages) | ternary('stopped', omit) }}" - enabled: "{{ ('systemd-journal-remote' in ansible_facts.packages) | ternary(false, omit) }}" + state: "{{ ('systemd-journal-upload' in ansible_facts.packages) | ternary('stopped', omit) }}" + enabled: "{{ ('systemd-journal-upload' in ansible_facts.packages) | ternary(false, omit) }}" masked: true loop: - systemd-journal-remote.socket From 2d1ae800b3a52890961537517bc4baa2c8e6260f Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Wed, 8 Apr 2026 16:10:55 +0100 Subject: [PATCH 09/10] fixed typo Signed-off-by: Mark Bolwell --- tasks/section_1/cis_1.4.x.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/section_1/cis_1.4.x.yml b/tasks/section_1/cis_1.4.x.yml index 7d7c3a6..2f49108 100644 --- a/tasks/section_1/cis_1.4.x.yml +++ b/tasks/section_1/cis_1.4.x.yml @@ -25,7 +25,7 @@ - name: "1.4.1 | PATCH | Ensure bootloader password is set" ansible.builtin.copy: dest: /boot/grub2/user.cfg - content: "GRUB2_PASSWORD={{ rhel9_compiled_bootloader_password }}" # noqa template-instead-of-copy + content: "GRUB2_PASSWORD={{ rhel9cis_compiled_bootloader_password }}" # noqa template-instead-of-copy owner: root group: root mode: 'go-rwx' From 2ac71da85c0fb34ce02ce2d037c50f5b919f5168 Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Fri, 10 Apr 2026 16:54:31 +0100 Subject: [PATCH 10/10] updated handlers Signed-off-by: Mark Bolwell --- handlers/main.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/handlers/main.yml b/handlers/main.yml index c6de8f3..45432a5 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -246,18 +246,21 @@ ## Auditd tasks note order for handlers to run -- name: Auditd immutable check - ansible.builtin.command: grep -c "^-e 2" /etc/audit/rules.d/99_auditd.rules - changed_when: false - register: discovered_auditd_immutable_check +- name: Auditd rules reload + when: prelim_auditd_immutable_check.rc == 1 or discovered_augenrules_check.stdout is search('No change') + ansible.builtin.command: augenrules --load + changed_when: true + failed_when: discovered_augenrule_check.rc not in [ 0, 1 ] + register: discovered_augenrule_check - name: Audit immutable fact - when: discovered_auditd_immutable_check.stdout == '1' + when: prelim_auditd_immutable_check is defined ansible.builtin.debug: msg: "Reboot required for auditd to apply new rules as immutable set" notify: Set reboot required - name: Stop auditd process + when: prelim_auditd_immutable_check is defined ansible.builtin.command: systemctl kill auditd changed_when: true listen: Restart auditd