diff --git a/.github/workflows/devel_pipeline_validation.yml b/.github/workflows/devel_pipeline_validation.yml index 39af625..e02fe1f 100644 --- a/.github/workflows/devel_pipeline_validation.yml +++ b/.github/workflows/devel_pipeline_validation.yml @@ -1,138 +1,159 @@ --- - name: Devel pipeline - - on: # yamllint disable-line rule:truthy - pull_request_target: - types: [opened, reopened, synchronize] - branches: - - devel - paths: - - '**.yml' - - '**.sh' - - '**.j2' - - '**.ps1' - - '**.cfg' - - # 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 - - steps: - - uses: actions/first-interaction@main - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - 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: ubuntu-latest - env: - ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }} - # Imported as a variable by terraform - TF_VAR_repository: ${{ github.event.repository.name }} - defaults: - run: - shell: bash - working-directory: .github/workflows/github_linux_IaC - - steps: - - name: Clone ${{ github.event.repository.name }} - uses: actions/checkout@v4 + name: Devel pipeline + + on: # yamllint disable-line rule:truthy + pull_request_target: + types: [opened, reopened, synchronize] + branches: + - devel + paths: + - '**.yml' + - '**.sh' + - '**.j2' + - '**.ps1' + - '**.cfg' + # Allow manual running of workflow + workflow_dispatch: + + # 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 will create messages for first time contributers and direct them to the Discord server + welcome: + runs-on: self-hosted + + steps: + - uses: actions/first-interaction@main with: - ref: ${{ github.event.pull_request.head.sha }} - - # 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 - - - name: Add_ssh_key - working-directory: .github/workflows - env: - SSH_AUTH_SOCK: /tmp/ssh_agent.sock - PRIVATE_KEY: "${{ secrets.SSH_PRV_KEY }}" - run: | - mkdir .ssh - chmod 700 .ssh - echo $PRIVATE_KEY > .ssh/github_actions.pem - chmod 600 .ssh/github_actions.pem - - - 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: Terraform_Init - id: init - run: terraform 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: Terraform_Validate - id: validate - run: terraform 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: Terraform_Apply - id: apply - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - run: terraform apply -var-file "github_vars.tfvars" -var-file "${OSVAR}.tfvars" --auto-approve -input=false - - ## Debug Section - - 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 - - - name: Sleep for 60 seconds - run: sleep ${{ vars.BUILD_SLEEPTIME }} - - # Run the Ansible playbook - - name: Run_Ansible_Playbook - uses: arillso/action.playbook@master - with: - playbook: site.yml - inventory: .github/workflows/github_linux_IaC/hosts.yml - galaxy_file: collections/requirements.yml - private_key: ${{ secrets.SSH_PRV_KEY }} - # verbose: 3 - env: - ANSIBLE_HOST_KEY_CHECKING: "false" - ANSIBLE_DEPRECATION_WARNINGS: "false" - - # Remove test system - User secrets to keep if necessary - - - name: Terraform_Destroy - if: always() && env.ENABLE_DEBUG == 'false' - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - run: terraform destroy -var-file "github_vars.tfvars" -var-file "${OSVAR}.tfvars" --auto-approve -input=false + repo-token: ${{ secrets.GITHUB_TOKEN }} + 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 + 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: + + - name: Git clone the lockdown repository to test + uses: actions/checkout@v4 + 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 + + + # 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 }} + + # 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" + echo "PRIVSUBNET_ID = $AWS_PRIVSUBNET_ID" + echo "VPC_ID" = $AWS_VPC_SECGRP_ID" + 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 }} + PRIVSUBNET_ID: ${{ secrets.AWS_PRIVSUBNET_ID }} + VPC_ID: ${{ secrets.AWS_VPC_SECGRP_ID }} + + - 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 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 + +## Debug Section + - 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 + + - 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 + + # 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 diff --git a/.github/workflows/main_pipeline_validation.yml b/.github/workflows/main_pipeline_validation.yml index 8ded701..4a5adc9 100644 --- a/.github/workflows/main_pipeline_validation.yml +++ b/.github/workflows/main_pipeline_validation.yml @@ -1,127 +1,156 @@ --- - name: Main pipeline - - on: # yamllint disable-line rule:truthy - pull_request_target: - types: [opened, reopened, synchronize] - branches: - - main - paths: - - '**.yml' - - '**.sh' - - '**.j2' - - '**.ps1' - - '**.cfg' - - # 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: ubuntu-latest - env: - ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }} - # Imported as a variable by terraform - TF_VAR_repository: ${{ github.event.repository.name }} - defaults: - run: - shell: bash - working-directory: .github/workflows/github_linux_IaC - - steps: - - name: Clone ${{ github.event.repository.name }} - uses: actions/checkout@v4 + name: Main pipeline + + on: # yamllint disable-line rule:truthy + pull_request_target: + types: [opened, reopened, synchronize] + branches: + - main + paths: + - '**.yml' + - '**.sh' + - '**.j2' + - '**.ps1' + - '**.cfg' + + # 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 will create messages for first time contributers and direct them to the Discord server + welcome: + runs-on: self-hosted + + steps: + - uses: actions/first-interaction@main with: - ref: ${{ github.event.pull_request.head.sha }} - - # 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 - - - name: Add_ssh_key - working-directory: .github/workflows - env: - SSH_AUTH_SOCK: /tmp/ssh_agent.sock - PRIVATE_KEY: "${{ secrets.SSH_PRV_KEY }}" - run: | - mkdir .ssh - chmod 700 .ssh - echo $PRIVATE_KEY > .ssh/github_actions.pem - chmod 600 .ssh/github_actions.pem - - - 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: Terraform_Init - id: init - run: terraform 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: Terraform_Validate - id: validate - run: terraform 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: Terraform_Apply - id: apply - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - run: terraform apply -var-file "github_vars.tfvars" -var-file "${OSVAR}.tfvars" --auto-approve -input=false - - ## Debug Section - - 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 - - - name: Sleep for 60 seconds - run: sleep ${{ vars.BUILD_SLEEPTIME }} - - # Run the Ansible playbook - - name: Run_Ansible_Playbook - uses: arillso/action.playbook@master - with: - playbook: site.yml - inventory: .github/workflows/github_linux_IaC/hosts.yml - galaxy_file: collections/requirements.yml - private_key: ${{ secrets.SSH_PRV_KEY }} - # verbose: 3 - env: - ANSIBLE_HOST_KEY_CHECKING: "false" - ANSIBLE_DEPRECATION_WARNINGS: "false" - - # Remove test system - User secrets to keep if necessary - - - name: Terraform_Destroy - if: always() && env.ENABLE_DEBUG == 'false' - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - run: terraform destroy -var-file "github_vars.tfvars" -var-file "${OSVAR}.tfvars" --auto-approve -input=false + repo-token: ${{ secrets.GITHUB_TOKEN }} + 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 + 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: + + - name: Git clone the lockdown repository to test + uses: actions/checkout@v4 + 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 + + # 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 }} + + # 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" + echo "PRIVSUBNET_ID = $AWS_PRIVSUBNET_ID" + echo "VPC_ID" = $AWS_VPC_SECGRP_ID" + 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 }} + PRIVSUBNET_ID: ${{ secrets.AWS_PRIVSUBNET_ID }} + VPC_ID: ${{ secrets.AWS_VPC_SECGRP_ID }} + + - 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 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 + +## Debug Section + - 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 + + - 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 + + # 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 diff --git a/.github/workflows/update_galaxy.yml b/.github/workflows/update_galaxy.yml index f935280..b6ee6a1 100644 --- a/.github/workflows/update_galaxy.yml +++ b/.github/workflows/update_galaxy.yml @@ -1,19 +1,19 @@ --- -name: update galaxy + name: update galaxy -on: - push: - branches: - - main -jobs: - update_role: - runs-on: ubuntu-latest - steps: - - name: Checkout repo - uses: actions/checkout@v4 + on: + push: + branches: + - main + jobs: + update_role: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 - - name: Action Ansible Galaxy Release ${{ github.ref_name }} - uses: ansible-actions/ansible-galaxy-action@main - with: - galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} + - name: Action Ansible Galaxy Release ${{ github.ref_name }} + uses: ansible-actions/ansible-galaxy-action@main + with: + galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 71a7e81..e3bd170 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,17 +30,17 @@ repos: # Scan for passwords - repo: https://github.com/Yelp/detect-secrets - rev: v1.4.0 + rev: v1.5.0 hooks: - id: detect-secrets - repo: https://github.com/gitleaks/gitleaks - rev: v8.18.2 + rev: v8.18.4 hooks: - id: gitleaks - repo: https://github.com/ansible-community/ansible-lint - rev: v24.2.2 + rev: v24.7.0 hooks: - id: ansible-lint name: Ansible-lint diff --git a/Changelog.md b/Changelog.md index f2d02d0..f38e3af 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,16 @@ # Changes to RHEL8STIG -## 3.2 - STIV V1R13 - 24th Jan 2024 +## 3.3 - STIG V1R13 - 24th Jan 2024 + +- updated audit variables +- workflow updates +- #277 thanks to @BJSmithIEEE +- #278 thanks to @prestonSeaman2 +- #299 thanks to @derekbentson +- removed dependency on jmespath +- updated 010120 prelim and idempotency + +## 3.2 - STIG V1R13 - 24th Jan 2024 - Audit updated - moved audit into prelim diff --git a/README.md b/README.md index 98fbeab..68ea015 100644 --- a/README.md +++ b/README.md @@ -84,9 +84,8 @@ The following packages must be installed on the controlling host/host where ansi - python2-passlib (or just passlib, if using python3) - python-lxml - python-xmltodict -- python-jmespath -Package 'python-xmltodict' is required if you enable the OpenSCAP tool installation and run a report. Packages python(2)-passlib and python-jmespath are required for tasks with custom filters or modules. These are all required on the controller host that executes Ansible. +Package 'python-xmltodict' is required if you enable the OpenSCAP tool installation and run a report. Packages python(2)-passlib are required for tasks with custom filters or modules. These are all required on the controller host that executes Ansible. ## Role Variables diff --git a/defaults/main.yml b/defaults/main.yml index 2169f0e..ef4fc82 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -550,10 +550,18 @@ rhel8stig_var_log_perm: 0755 rhel8stig_sys_commands_perm: 0755 # RHEL-08-010330 -# rhel8stig_lib_file_perm is the permissions teh library files will be set to +# rhel8stig_lib_file_perm is the permissions the library files will be set to # To conform to STIG standards this needs to be set to 755 or more restrictive rhel8stig_lib_file_perm: 755 +# RHEL-08-010380 +# rhel8stig_sudoers_exclude_nopasswd_list is exception list for not having the NOPASSWD removed +# +rhel8stig_sudoers_exclude_nopasswd_list: + - rocky + - ec2-user +# - vagrant + # RHEL-08-010480 # rhel8stig_ssh_pub_key_perm are the permissions set to the SSH public host keys # To conform to STIG standards this needs to be set to 0644 or less permissive @@ -834,10 +842,6 @@ rhel8stig_boot_part: "{{ rhel_08_boot_part.stdout }}" # RHEL-08-010740/RHEL-08-010750 rhel8stig_passwd_label: "{{ (this_item | default(item)).id }}: {{ (this_item | default(item)).dir }}" -# RHEL-08-010630/RHEL-08-010640/RHEL-08-010650 -rhel8stig_nfs_mounts: "{{ ansible_mounts | to_json | from_json | json_query(rhel8stig_nfs_mounts_query) }}" -rhel8stig_nfs_mounts_query: "[?starts_with(fstype, 'nfs')].mount" - # RHEL-08-010680 # This can be managed using a template ensure settings are correct rhel8_stig_use_resolv_template: false diff --git a/handlers/main.yml b/handlers/main.yml index cd5e482..9b8b7db 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -24,6 +24,7 @@ name: sshd state: restarted when: + - rhel_08_040159 - not rhel8stig_system_is_chroot - "'openssh-server' in ansible_facts.packages" - not change_requires_reboot @@ -43,19 +44,41 @@ - not rhel8stig_system_is_chroot - not change_requires_reboot +- name: restart rngd + ansible.builtin.service: + name: rngd.service + state: restarted + when: + - rhel_08_010471 + - name: restart rsyslog ansible.builtin.service: name: rsyslog state: restarted + when: + - rhel_08_010561 + +- name: restart firewalld + ansible.builtin.service: + name: firewalld + state: restarted + when: rhel_08_040101 + +- name: restart fapolicyd + ansible.builtin.service: + name: fapolicyd + state: restarted + when: rhel_08_040136 - name: generate fapolicyd rules ansible.builtin.shell: fagenrules --load when: rhel_08_040137_rules_dir.stat.exists -- name: restart fapolicyd +- name: restart usbguard ansible.builtin.service: - name: fapolicyd + name: usbguard state: restarted + when: rhel_08_040141 - name: confirm grub2 user cfg ansible.builtin.stat: @@ -112,6 +135,7 @@ - not rhel8stig_system_is_chroot - not system_is_container - not change_requires_reboot + - rhel_08_030181 - name: rebuild initramfs ansible.builtin.shell: dracut -f diff --git a/meta/main.yml b/meta/main.yml index a9a9978..b304b26 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -6,7 +6,7 @@ galaxy_info: license: MIT role_name: rhel8_stig namespace: mindpointgroup - min_ansible_version: '2.10.1' + min_ansible_version: '2.11.1' platforms: - name: EL versions: diff --git a/tasks/audit_only.yml b/tasks/audit_only.yml index 864f5bb..ab5a573 100644 --- a/tasks/audit_only.yml +++ b/tasks/audit_only.yml @@ -22,7 +22,7 @@ when: - audit_only ansible.builtin.debug: - msg: "The Audit results are: {{ pre_audit_summary }}." + msg: "{{ audit_results.split('\n') }}" - name: Audit_only | Stop Playbook Audit Only selected when: diff --git a/tasks/fix-cat1.yml b/tasks/fix-cat1.yml index 04597be..a620305 100644 --- a/tasks/fix-cat1.yml +++ b/tasks/fix-cat1.yml @@ -44,12 +44,12 @@ - name: "HIGH | RHEL-08-010020 | AUDIT | Check for GRUB_CMDLINE_LINUX in /etc/default/grub" ansible.builtin.shell: grep -P '^\s*GRUB_CMDLINE_LINUX=".*"$' /etc/default/grub - check_mode: false - failed_when: false changed_when: rhel_08_010020_default_grub_missing_audit.rc > 0 + failed_when: false + check_mode: false register: rhel_08_010020_default_grub_missing_audit - - name: "HIGH | RHEL-08-010020 | AUDIT | parse sane GRUB_CMDLINE_LINUX from /proc/cmdline" + - name: "HIGH | RHEL-08-010020 | AUDIT | Parse sane GRUB_CMDLINE_LINUX from /proc/cmdline" ansible.builtin.shell: grep -oP ' ro \K.*?(?= ?LANG=)' /proc/cmdline check_mode: false changed_when: false @@ -68,6 +68,13 @@ grub_cmdline_linux: "{{ rhel_08_010020_grub_cmdline_linux_audit.stdout }}" when: rhel_08_010020_default_grub_missing_audit is changed # noqa no-handler + - name: "HIGH | RHEL-08-010020 | AUDIT | Verify fips kernel parameters in /etc/default/grub" + ansible.builtin.shell: grep -P '^\s*GRUB_CMDLINE_LINUX=".*(?<=[" ])fips=1(?=[" ]).*"$' /etc/default/grub + check_mode: false + changed_when: false + failed_when: rhel_08_010020_fips_kernel_set.rc not in [ 0, 1 ] + register: rhel_08_010020_fips_kernel_set + - name: "HIGH | RHEL-08-010020 | PATCH | fips=1 must be in /etc/default/grub" ansible.builtin.replace: path: /etc/default/grub @@ -81,27 +88,35 @@ when: - not ansible_check_mode or rhel_08_010020_default_grub_missing_audit is not changed + - rhel_08_010020_fips_kernel_set.stdout | length == 0 notify: - confirm grub2 user cfg - change_requires_reboot + - name: "HIGH | RHEL-08-010020 | AUDIT | Verify boot kernel parameters in /etc/default/grub" + ansible.builtin.shell: grep -P '^\s*GRUB_CMDLINE_LINUX=".*(?<=[" ])boot=UUID={{ rhel8stig_boot_uuid.stdout }}(?=[" ]).*"$' /etc/default/grub + check_mode: false + changed_when: false + failed_when: rhel_08_010020_boot_kernel_set.rc not in [ 0, 1 ] + register: rhel_08_010020_boot_kernel_set + - name: "HIGH | RHEL-08-010020 | PATCH | If /boot or /boot/efi reside on separate partitions, the kernel parameter boot= must be added to the kernel command line." ansible.builtin.replace: path: /etc/default/grub regexp: "{{ rhel8stig_regexp_quoted_params }}" replace: "{{ rhel8stig_replace_quoted_params }}" - with_items: - - "{{ ansible_mounts | json_query(query) }}" # noqa: jinja[invalid] vars: - query: "[?mount=='{{ rhel8stig_boot_part.stdout }}'] | [0]" + query: "{{ rhel8stig_boot_part.stdout }}" key: GRUB_CMDLINE_LINUX param: boot - value: UUID={{ item.uuid }} + value: UUID={{ rhel8stig_boot_uuid.stdout }} insert: true when: - rhel8stig_boot_part.stdout not in ['/', ''] + - rhel_08_010020_boot_kernel_set.stdout | length == 0 - not ansible_check_mode or rhel_08_010020_default_grub_missing_audit is not changed + notify: confirm grub2 user cfg register: result @@ -110,9 +125,7 @@ check_mode: false with_items: - fips=1 - - boot=UUID={{ ansible_mounts | json_query(query) }} - vars: - query: "[?mount=='{{ rhel8stig_boot_part.stdout }}'].uuid | [0]" # noqa: jinja[invalid] + - boot=UUID={{ rhel8stig_boot_uuid.stdout }} register: rhel_08_010020_audit when: - not ansible_check_mode or diff --git a/tasks/fix-cat2.yml b/tasks/fix-cat2.yml index 50effba..ec4bce8 100644 --- a/tasks/fix-cat2.yml +++ b/tasks/fix-cat2.yml @@ -1338,7 +1338,7 @@ - name: "MEDIUM | RHEL-08-010380 | PATCH | RHEL 8 must require users to provide a password for privilege escalation." ansible.builtin.replace: path: "{{ item }}" - regexp: '^([^#|{% if system_is_ec2 %}ec2-user{% endif %}].*)NOPASSWD(.*)' + regexp: '^((?!#|{% for name in rhel8stig_sudoers_exclude_nopasswd_list %}{{ name }}{% if not loop.last -%}|{%- endif -%}{% endfor %}).*)NOPASSWD(.*)' replace: '\1PASSWD\2' with_items: - "{{ rhel8stig_sudoers_files.stdout_lines }}" @@ -1801,8 +1801,8 @@ - name: "MEDIUM | RHEL-08-010561 | PATCH | The rsyslog service must be running in RHEL 8." ansible.builtin.service: name: rsyslog.service - state: started enabled: true + notify: restart rsyslog when: - rhel_08_010561 tags: @@ -1816,17 +1816,15 @@ - name: "MEDIUM | RHEL-08-010570 | PATCH | RHEL 8 must prevent files with the setuid and setgid bit set from being executed on file systems that contain user home directories." ansible.posix.mount: - path: /home + path: "{{ item.mount }}" state: mounted - src: "{{ home_mount.device }}" - fstype: "{{ home_mount.fstype }}" - opts: "{{ home_mount.options }},nosuid" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + opts: "defaults{{ rhel_08_010570| ternary (',nosuid', '') }}" + loop: "{{ ansible_facts.mounts }}" when: + - item.mount == '/home' - rhel_08_010570 - - ansible_mounts | selectattr('mount', 'match', '^/home$') | list | length != 0 - - "'nosuid' not in home_mount.options" - vars: - home_mount: "{{ ansible_mounts | json_query('[?mount == `/home`] | [0]') }}" # noqa: jinja[invalid] tags: - RHEL-08-010570 - CAT2 @@ -1839,17 +1837,15 @@ - name: "MEDIUM | RHEL-08-010571 | PATCH | RHEL 8 must prevent files with the setuid and setgid bit set from being executed on the /boot directory." ansible.posix.mount: - path: /boot + path: "{{ item.mount }}" state: mounted - src: "{{ boot_mount.device }}" - fstype: "{{ boot_mount.fstype }}" - opts: "{{ boot_mount.options }},nosuid" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + opts: "defaults{{ rhel_08_010571| ternary (',nosuid', '') }}" + loop: "{{ ansible_facts.mounts }}" when: + - item.mount == '/boot' - rhel_08_010571 - - ansible_mounts | selectattr('mount', 'match', '^/boot$') | list | length != 0 - - "'nosuid' not in boot_mount.options" - vars: - boot_mount: "{{ ansible_mounts | json_query('[?mount == `/boot`] | [0]') }}" # noqa: jinja[invalid] tags: - RHEL-08-010571 - CAT2 @@ -1862,17 +1858,15 @@ - name: "MEDIUM | RHEL-08-010572 | PATCH | RHEL 8 must prevent files with the setuid and setgid bit set from being executed on the /boot/efi directory." ansible.posix.mount: - path: /boot/efi + path: "{{ item.mount }}" state: mounted - src: "UUID={{ boot_efi_mount.uuid }}" - fstype: "{{ boot_efi_mount.fstype }}" - opts: "{{ boot_efi_mount.options }},nosuid" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + opts: "defaults{{ rhel_08_010572| ternary (',nosuid', '') }}" + loop: "{{ ansible_facts.mounts }}" when: + - item.mount == '/boot/efi' - rhel_08_010572 - - ansible_mounts | selectattr('mount', 'match', '^/boot/efi$') | list | length != 0 - - "'nosuid' not in boot_efi_mount.options" - vars: - boot_efi_mount: "{{ ansible_mounts | json_query('[?mount == `/boot/efi`] | [0]') }}" # noqa: jinja[invalid] tags: - RHEL-08-010572 - CAT2 @@ -1938,17 +1932,16 @@ - name: "MEDIUM | RHEL-08-010590 | PATCH | RHEL 8 must prevent code from being executed on file systems that contain user home directories." ansible.posix.mount: - path: /home + path: "{{ item.mount }}" state: mounted - src: "{{ home_mount.device }}" - fstype: "{{ home_mount.fstype }}" - opts: "{{ home_mount.options }},{% if rhel_08_010570 is sameas true %}nosuid,{% endif %}noexec" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + opts: "{{ item.options }},{% if rhel_08_010570 is sameas true %}nosuid,{% endif %}noexec" + loop: "{{ ansible_facts.mounts }}" when: - rhel_08_010590 - - ansible_mounts | selectattr('mount', 'match', '^/home$') | list | length != 0 - - "'noexec' not in home_mount.options" - vars: - home_mount: "{{ ansible_mounts | json_query('[?mount == `/home`] | [0]') }}" # noqa: jinja[invalid] + - item.mount == '/home' + - "'noexec' not in item.options" tags: - RHEL-08-010590 - CAT2 @@ -1966,31 +1959,29 @@ block: - name: "MEDIUM | RHEL-08-010600 | PATCH | RHEL 8 must prevent special devices on file systems that are used with removable media. | Set nodev to /media" ansible.posix.mount: - path: /media + path: "{{ item.mount }}" state: mounted - src: "{{ removable_mount.device }}" - fstype: "{{ removable_mount.fstype }}" - opts: "{{ removable_mount.options }},nodev" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + opts: "{{ item.options }},nodev" + loop: "{{ ansible_facts.mounts }}" when: + - item.mount == '/media' - rhel_08_010600 - - ansible_mounts | selectattr('mount', 'match', '^/media$') | list | length != 0 - - "'nodev' not in home_mount.options" - vars: - removable_mount: "{{ ansible_mounts | json_query('[?mount == `/media`] | [0]') }}" # noqa: jinja[invalid] + - "'nodev' not in item.options" - name: "MEDIUM | RHEL-08-010600 | PATCH | RHEL 8 must prevent special devices on file systems that are used with removable media. | Set nodev to /mnt" ansible.posix.mount: - path: /mnt + path: "{{ item.mount }}" state: mounted - src: "{{ removable_mount2.device }}" - fstype: "{{ removable_mount2.fstype }}" - opts: "{{ removable_mount2.options }},nodev" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + opts: "{{ item.options }},nodev" + loop: "{{ ansible_facts.mounts }}" when: - rhel_08_010600 - - ansible_mounts | selectattr('mount', 'match', '^/mnt$') | list | length != 0 - - "'nodev' not in home_mount.options" - vars: - removable_mount2: "{{ ansible_mounts | json_query('[?mount == `/mnt`] | [0]') }}" # noqa: jinja[invalid] + - item.mount == '/mnt' + - "'nodev' not in item.options" when: - rhel_08_010600 - not rhel8stig_system_is_chroot @@ -2008,31 +1999,29 @@ block: - name: "MEDIUM | RHEL-08-010610 | PATCH | RHEL 8 must prevent code from being executed on file systems that are used with removable media. | Set noexec to /media" ansible.posix.mount: - path: /media + path: "{{ item.mount }}" state: mounted - src: "{{ removable_mount.device }}" - fstype: "{{ removable_mount.fstype }}" - opts: "{{ removable_mount.options }},noexec" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + opts: "{{ item.options }},noexec" + loop: "{{ ansible_facts.mounts }}" when: - - rhel_08_010600 - - ansible_mounts | selectattr('mount', 'match', '^/media$') | list | length != 0 - - "'noexec' not in home_mount.options" - vars: - removable_mount: "{{ ansible_mounts | json_query('[?mount == `/media`] | [0]') }}" # noqa: jinja[invalid] + - rhel_08_010610 + - item.mount == '/media' + - "'noexec' not in item.options" - name: "MEDIUM | RHEL-08-010610 | PATCH | RHEL 8 must prevent code from being executed on file systems that are used with removable media. | Set noexec to /mnt" ansible.posix.mount: - path: /mnt + path: "{{ item.mount }}" state: mounted - src: "{{ removable_mount2.device }}" - fstype: "{{ removable_mount2.fstype }}" - opts: "{{ removable_mount2.options }},noexec" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + opts: "{{ item.options }},noexec" + loop: "{{ ansible_facts.mounts }}" when: - rhel_08_010610 - - ansible_mounts | selectattr('mount', 'match', '^/mnt$') | list | length != 0 - - "'noexec' not in home_mount.options" - vars: - removable_mount2: "{{ ansible_mounts | json_query('[?mount == `/mnt`] | [0]') }}" # noqa: jinja[invalid] + - item.mount == '/mnt' + - "'noexec' not in item.options" when: - rhel_08_010610 - not rhel8stig_system_is_chroot @@ -2050,31 +2039,30 @@ block: - name: "MEDIUM | RHEL-08-010620 | PATCH | RHEL 8 must prevent files with the setuid and setgid bit set from being executed on file systems that are used with removable media. | Set nosuid to /media" ansible.posix.mount: - path: /media + ansible.posix.mount: + path: "{{ item.mount }}" state: mounted - src: "{{ removable_mount.device }}" - fstype: "{{ removable_mount.fstype }}" - opts: "{{ removable_mount.options }},nosuid" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + opts: "{{ item.options }},nosuid" + loop: "{{ ansible_facts.mounts }}" when: - rhel_08_010620 - - ansible_mounts | selectattr('mount', 'match', '^/media$') | list | length != 0 - - "'nosuid' not in home_mount.options" - vars: - removable_mount: "{{ ansible_mounts | json_query('[?mount == `/media`] | [0]') }}" # noqa: jinja[invalid] + - item.mount == '/media' + - "'nosuid' not in item.options" - name: "MEDIUM | RHEL-08-010620 | PATCH | RHEL 8 must prevent files with the setuid and setgid bit set from being executed on file systems that are used with removable media. | Set nosuid to /mnt" ansible.posix.mount: - path: /mnt + path: "{{ item.mount }}" state: mounted - src: "{{ removable_mount2.device }}" - fstype: "{{ removable_mount2.fstype }}" - opts: "{{ removable_mount2.options }},nosuid" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + opts: "{{ item.options }},nosuid" + loop: "{{ ansible_facts.mounts }}" when: - rhel_08_010620 - - ansible_mounts | selectattr('mount', 'match', '^/mnt$') | list | length != 0 - - "'nosuid' not in home_mount.options" - vars: - removable_mount2: "{{ ansible_mounts | json_query('[?mount == `/mnt`] | [0]') }}" # noqa: jinja[invalid] + - item.mount == '/mnt' + - "'nosuid' not in item.options" when: - rhel_08_010620 - not rhel8stig_system_is_chroot @@ -2090,19 +2078,16 @@ - name: "MEDIUM | RHEL-08-010630 | PATCH | RHEL 8 must prevent code from being executed on file systems that are imported via Network File System (NFS)." ansible.posix.mount: - path: "{{ item }}" - src: "{{ ansible_mounts | json_query(device_query) }}" - fstype: "{{ ansible_mounts | json_query(fstype_query) }}" - opts: "{{ ansible_mounts | json_query(options_query) }},noexec" + path: "{{ item.mount }}" + fstype: "{{ item.fstype }}" + src: "{{ item.device }}" + opts: "{{ item.options }},noexec" state: mounted - vars: - device_query: '[?mount == `{{ item }}`] | [0].device' # noqa: jinja[invalid] - fstype_query: '[?mount == `{{ item }}`] | [0].fstype' # noqa: jinja[invalid] - options_query: '[?mount == `{{ item }}`] | [0].options' # noqa: jinja[invalid] - with_items: "{{ rhel8stig_nfs_mounts }}" + loop: "{{ ansible_facts.mounts }}" when: - rhel_08_010630 - - "'noexec' not in (ansible_mounts | json_query(options_query))" + - "'nfs' in item.fstype" + - "'noexec' not in item.options" tags: - RHEL-08-010630 - CAT2 @@ -2115,19 +2100,16 @@ - name: "MEDIUM | RHEL-08-010640 | PATCH | RHEL 8 must prevent special devices on file systems that are imported via Network File System (NFS)." ansible.posix.mount: - path: "{{ item }}" - src: "{{ ansible_mounts | json_query(device_query) }}" - fstype: "{{ ansible_mounts | json_query(fstype_query) }}" - opts: "{{ ansible_mounts | json_query(options_query) }},nodev" + path: "{{ item.mount }}" + fstype: "{{ item.fstype }}" + src: "{{ item.device }}" + opts: "{{ item.options }},{% if rhel_08_010630 is sameas true %}noexec,{% endif %}nodev" state: mounted - vars: - device_query: '[?mount == `{{ item }}`] | [0].device' # noqa: jinja[invalid] - fstype_query: '[?mount == `{{ item }}`] | [0].fstype' # noqa: jinja[invalid] - options_query: '[?mount == `{{ item }}`] | [0].options' # noqa: jinja[invalid] - with_items: "{{ rhel8stig_nfs_mounts }}" + loop: "{{ ansible_facts.mounts }}" when: - rhel_08_010640 - - "'nodev' not in (ansible_mounts | json_query(options_query))" + - "'nfs' in item.fstype" + - "'nodev' not in item.options" tags: - RHEL-08-010640 - CAT2 @@ -2140,19 +2122,16 @@ - name: "MEDIUM | RHEL-08-010650 | PATCH | RHEL 8 must prevent files with the setuid and setgid bit set from being executed on file systems that are imported via Network File System (NFS)" ansible.posix.mount: - path: "{{ item }}" - src: "{{ ansible_mounts | json_query(device_query) }}" - fstype: "{{ ansible_mounts | json_query(fstype_query) }}" - opts: "{{ ansible_mounts | json_query(options_query) }},nosuid" + path: "{{ item.mount }}" + fstype: "{{ item.fstype }}" + src: "{{ item.device }}" + opts: "{{ item.options }},{% if rhel_08_010630 is sameas true %}noexec,{% endif %}{% if rhel_08_010640 is sameas true %}nodev,{% endif %}nosuid" state: mounted - vars: - device_query: '[?mount == `{{ item }}`] | [0].device' # noqa: jinja[invalid] - fstype_query: '[?mount == `{{ item }}`] | [0].fstype' # noqa: jinja[invalid] - options_query: '[?mount == `{{ item }}`] | [0].options' # noqa: jinja[invalid] - with_items: "{{ rhel8stig_nfs_mounts }}" + loop: "{{ ansible_facts.mounts }}" when: - rhel_08_010650 - - "'nosuid' not in (ansible_mounts | json_query(options_query))" + - "'nfs' in item.fstype" + - "'nosuid' not in item.options" tags: - RHEL-08-010650 - CAT2 @@ -2728,7 +2707,7 @@ when: - rhel_08_010800 - rhel8stig_complex - - ansible_mounts | selectattr('mount', 'match', '^/home$') | list | length == 0 + - "'/home' not in ansible_facts.mounts" tags: - RHEL-08-010800 - CAT2 @@ -4367,10 +4346,9 @@ path: "{{ item }}" regexp: "umask\\s+(?!{{ rhel8stig_login_defaults.umask | default('077') }})" state: absent - with_items: - - "{{ rhel8stig_020352_file | json_query('results[*].files[*].path') | flatten }}" # noqa: jinja[invalid] + loop: "{{ rhel8stig_020352_file.stdout_lines }}" when: - - (rhel8stig_020352_file | json_query('results[*].files[*].path') | flatten ) is defined + - rhel8stig_020352_file.stdout_lines is defined when: - rhel_08_020352 tags: @@ -4848,17 +4826,9 @@ - auditd - name: "MEDIUM | RHEL-08-030180 | PATCH | The RHEL 8 audit package must be installed." - block: - - name: "MEDIUM | RHEL-08-030180 | PATCH | The RHEL 8 audit package must be installed. | Install audit" - ansible.builtin.package: - name: audit - state: present - - - name: "MEDIUM | RHEL-08-030180 | PATCH | The RHEL 8 audit package must be installed. | Enable and start service" - ansible.builtin.service: - name: auditd - enabled: true - state: started + ansible.builtin.package: + name: audit + state: present when: - rhel_08_030180 tags: @@ -4874,8 +4844,8 @@ - name: "MEDIUM | RHEL-08-030181 | PATCH | RHEL 8 audit records must contain information to establish what type of events occurred, the source of events, where events occurred, and the outcome of events." ansible.builtin.service: name: auditd - state: started enabled: true + notify: restart auditd when: - rhel_08_030181 tags: @@ -5992,12 +5962,6 @@ name: iptables-services state: present when: rhel8stig_firewall_service == "iptables" - - - name: "MEDIUM | RHEL-08-040100 | PATCH | A firewall must be installed on RHEL 8. | Start and enable service" - ansible.builtin.service: - name: "{{ rhel8stig_firewall_service }}" - state: started - enabled: true when: - rhel_08_040100 - rhel8stig_firewall_service != "not_required" @@ -6022,7 +5986,7 @@ - name: "MEDIUM | RHEL-08-040101 | PATCH | A firewall must be active on RHEL 8 | Enable the service" ansible.builtin.systemd: name: firewalld - state: started + state: started # Needs to start here or subsequent controls will fail enabled: true when: - rhel_08_040101 @@ -6213,12 +6177,15 @@ "MEDIUM | RHEL-08-040121 | PATCH | RHEL 8 must mount /dev/shm with the nosuid option." "MEDIUM | RHEL-08-040122 | PATCH | RHEL 8 must mount /dev/shm with the noexec option." ansible.posix.mount: - path: /dev/shm + path: "{{ item.mount }}" state: mounted - src: tmpfs - fstype: tmpfs + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" opts: "defaults{{ rhel_08_040120 | ternary (',nodev', '') }}{{ rhel_08_040121 | ternary (',nosuid', '') }}{{ rhel_08_040122 | ternary (',noexec', '') }}" - when: rhel8stig_040120_dev_shm_status.stdout | length > 0 + loop: "{{ ansible_facts.mounts }}" + when: + - item.mount == '/dev/shm' + - rhel8stig_040120_dev_shm_status.stdout | length > 0 when: - rhel_08_040120 or rhel_08_040121 or @@ -6257,14 +6224,15 @@ "MEDIUM | RHEL-08-040124 | PATCH | RHEL 8 must mount /tmp with the nosuid option." "MEDIUM | RHEL-08-040125 | PATCH | RHEL 8 must mount /tmp with the noexec option." ansible.posix.mount: - path: /tmp + path: "{{ item.mount }}" state: mounted - src: "{{ tmp_mount.device }}" - fstype: "{{ tmp_mount.fstype }}" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" opts: "defaults{{ rhel_08_040123 | ternary (',nodev', '') }}{{ rhel_08_040124 | ternary (',nosuid', '') }}{{ rhel_08_040125 | ternary (',noexec', '') }}" - vars: - tmp_mount: "{{ ansible_mounts | json_query('[?mount == `/tmp`] | [0]') }}" # noqa: jinja[invalid] - when: rhel8stig_040123_dev_status.stdout | length > 0 + loop: "{{ ansible_facts.mounts }}" + when: + - rhel8stig_040123_dev_status.stdout | length > 0 + - item.mount =='/tmp' when: - rhel_08_040123 or @@ -6294,7 +6262,7 @@ "MEDIUM | RHEL-08-040126 | PATCH | RHEL 8 must mount /var/log with the nodev option." "MEDIUM | RHEL-08-040127 | PATCH | RHEL 8 must mount /var/log with the nosuid option." "MEDIUM | RHEL-08-040128 | PATCH | RHEL 8 must mount /var/log with the noexec option." - ansible.builtin.shell: mount | grep -w "/var/log " + ansible.builtin.shell: mount | grep '\s\+/var/log\s\+' changed_when: false failed_when: false register: rhel8stig_040126_var_log_status @@ -6304,14 +6272,15 @@ "MEDIUM | RHEL-08-040127 | PATCH | RHEL 8 must mount /var/log with the nosuid option." "MEDIUM | RHEL-08-040128 | PATCH | RHEL 8 must mount /var/log with the noexec option." ansible.posix.mount: - path: /var/log + path: "{{ item.mount }}" state: mounted - src: "{{ var_log_mount.device }}" - fstype: "{{ var_log_mount.fstype }}" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" opts: "defaults{{ rhel_08_040126 | ternary (',nodev', '') }}{{ rhel_08_040127 | ternary (',nosuid', '') }}{{ rhel_08_040128 | ternary (',noexec', '') }}" - vars: - var_log_mount: "{{ ansible_mounts | json_query('[?mount == `/var/log`] | [0]') }}" # noqa: jinja[invalid] - when: rhel8stig_040126_var_log_status.stdout | length > 0 + loop: "{{ ansible_facts.mounts }}" + when: + - rhel8stig_040126_var_log_status.stdout | length > 0 + - item.mount == '/var/log' when: - rhel_08_040126 or rhel_08_040127 or @@ -6350,14 +6319,15 @@ "MEDIUM | RHEL-08-040130 | PATCH | RHEL 8 must mount /var/log/audit with the nosuid option." "MEDIUM | RHEL-08-040131 | PATCH | RHEL 8 must mount /var/log/audit with the noexec option." ansible.posix.mount: - path: /var/log/audit + path: "{{ item.mount }}" state: mounted - src: "{{ audit_mount.device }}" - fstype: "{{ audit_mount.fstype }}" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" opts: "defaults{{ rhel_08_040129 | ternary (',nodev', '') }}{{ rhel_08_040130 | ternary (',nosuid', '') }}{{ rhel_08_040131 | ternary (',noexec', '') }}" - vars: - audit_mount: "{{ ansible_mounts | json_query('[?mount == `/var/log/audit`] | [0]') }}" # noqa: jinja[invalid] - when: rhel8stig_040129_var_log_audit_status.stdout | length > 0 + loop: "{{ ansible_facts.mounts }}" + when: + - item.mount == '/var/log/audit' + - rhel8stig_040129_var_log_audit_status.stdout | length > 0 when: - rhel_08_040129 or rhel_08_040130 or @@ -6396,14 +6366,15 @@ "MEDIUM | RHEL-08-040133 | PATCH | RHEL 8 must mount /var/tmp with the nosuid option." "MEDIUM | RHEL-08-040134 | PATCH | RHEL 8 must mount /var/tmp with the noexec option." ansible.posix.mount: - path: /var/tmp + path: "{{ item.mount }}" state: mounted - src: "{{ var_tmp_mount.device }}" - fstype: "{{ var_tmp_mount.fstype }}" + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" opts: "defaults{{ rhel_08_040132 | ternary (',nodev', '') }}{{ rhel_08_040133 | ternary (',nosuid', '') }}{{ rhel_08_040134 | ternary (',noexec', '') }}" - vars: - var_tmp_mount: "{{ ansible_mounts | json_query('[?mount == `/var/tmp`] | [0]') }}" # noqa: jinja[invalid] - when: rhel8stig_040132_var_tmp_status.stdout | length > 0 + loop: "{{ ansible_facts.mounts }}" + when: + - item.mount == '/var/log/audit' + - rhel8stig_040132_var_tmp_status.stdout | length > 0 when: - rhel_08_040132 or rhel_08_040133 or @@ -6442,7 +6413,6 @@ - name: "MEDIUM | RHEL-08-040136 | PATCH | The RHEL 8 fapolicy module must be enabled." ansible.builtin.systemd: name: fapolicyd - state: started enabled: true when: - rhel_08_040136 @@ -6496,8 +6466,6 @@ regexp: '^permissive =' line: 'permissive = 0' create: true - notify: - - restart fapolicyd when: - rhel_08_040137 tags: @@ -6532,8 +6500,8 @@ - name: "MEDIUM | RHEL-08-040141 | PATCH | RHEL 8 must enable the USBGuard. | Start/Enable service" ansible.builtin.service: name: usbguard - state: started enabled: true + notify: restart usbguard when: - rhel_08_040141 - rhel_08_040139 or @@ -6590,8 +6558,8 @@ - name: "MEDIUM | RHEL-08-040160 | PATCH | All RHEL 8 networked systems must have and implement SSH to protect the confidentiality and integrity of transmitted and received information, as well as information during preparation for transmission. | Start/Enable ssh server" ansible.builtin.service: name: sshd - state: started enabled: true + notify: restart sshd when: - rhel_08_040159 or "'openssh-server' in ansible_facts.packages" diff --git a/tasks/fix-cat3.yml b/tasks/fix-cat3.yml index 6a8a5db..1813522 100644 --- a/tasks/fix-cat3.yml +++ b/tasks/fix-cat3.yml @@ -149,11 +149,12 @@ - name: "LOW | RHEL-08-010471 | PATCH | RHEL 8 must enable the hardware random number generator entropy gatherer service." ansible.builtin.systemd: name: rngd.service - state: started enabled: true + notify: restart rngd when: + - rhel_08_010472 - rhel_08_010471 - - "'rng-tools' in ansible_facts.packages" + when: - rhel_08_010471 or rhel_08_010472 diff --git a/tasks/main.yml b/tasks/main.yml index 96d3f1d..a0444be 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -92,7 +92,8 @@ - RHEL-08-010149 - name: Include OS specific variables - ansible.builtin.include_vars: "{{ ansible_facts.distribution }}.yml" + ansible.builtin.include_vars: + file: "{{ ansible_facts.distribution }}.yml" tags: - always @@ -129,27 +130,31 @@ - always - name: Include prelim tasks - ansible.builtin.import_tasks: prelim.yml + ansible.builtin.import_tasks: + file: prelim.yml tags: - prelim_tasks - run_audit - name: Include CAT I patches - ansible.builtin.import_tasks: fix-cat1.yml + ansible.builtin.import_tasks: + file: fix-cat1.yml when: rhel8stig_cat1_patch tags: - CAT1 - high - name: Include CAT II patches - ansible.builtin.import_tasks: fix-cat2.yml + ansible.builtin.import_tasks: + file: fix-cat2.yml when: rhel8stig_cat2_patch tags: - CAT2 - medium - name: Include CAT III patches - ansible.builtin.import_tasks: fix-cat3.yml + ansible.builtin.import_tasks: + file: fix-cat3.yml when: rhel8stig_cat3_patch tags: - CAT3 @@ -175,7 +180,8 @@ - rhel8stig_skip_reboot - name: Run post remediation audit - ansible.builtin.import_tasks: post_remediation_audit.yml + ansible.builtin.import_tasks: + file: post_remediation_audit.yml when: - run_audit tags: diff --git a/tasks/post_remediation_audit.yml b/tasks/post_remediation_audit.yml index b3111c8..d58e921 100644 --- a/tasks/post_remediation_audit.yml +++ b/tasks/post_remediation_audit.yml @@ -21,26 +21,24 @@ when: - audit_format == "json" block: - - name: capture data {{ post_audit_outfile }} - ansible.builtin.shell: "cat {{ post_audit_outfile }}" - register: post_audit + - name: Post Audit | Capture audit data if json format + ansible.builtin.shell: grep -E '"summary-line.*Count:.*Failed' "{{ post_audit_outfile }}" | cut -d'"' -f4 + register: post_audit_summary changed_when: false - - name: Capture post-audit result + - name: Post Audit | Set Fact for audit summary ansible.builtin.set_fact: - post_audit_summary: "{{ post_audit.stdout | from_json | json_query(summary) }}" - vars: - summary: summary."summary-line" + post_audit_results: "{{ post_audit_summary.stdout }}" - name: Post Audit | Capture audit data if documentation format when: - audit_format == "documentation" block: - - name: Post Audit | capture data {{ post_audit_outfile }} - ansible.builtin.shell: "tail -2 {{ post_audit_outfile }}" - register: post_audit + - name: Post Audit | Capture audit data if documentation format + ansible.builtin.shell: "tail -2 /opt/audit_ubuntu2204-CIS-UBUNTU22_1720624848.documentation" + register: post_audit_summary changed_when: false - - name: Post Audit | Capture post-audit result + - name: Post Audit | Set Fact for audit summary ansible.builtin.set_fact: - post_audit_summary: "{{ post_audit.stdout_lines }}" + post_audit_results: "{{ post_audit_summary.stdout }}" diff --git a/tasks/pre_remediation_audit.yml b/tasks/pre_remediation_audit.yml index d0137e8..a745826 100644 --- a/tasks/pre_remediation_audit.yml +++ b/tasks/pre_remediation_audit.yml @@ -91,31 +91,30 @@ when: - audit_format == "json" block: - - name: Pre Audit | Capture data {{ pre_audit_outfile }} - ansible.builtin.shell: "cat {{ pre_audit_outfile }}" - register: pre_audit + - name: Pre Audit | Capture audit data if json format + ansible.builtin.shell: grep -E '\"summary-line.*Count:.*Failed' "{{ pre_audit_outfile }}" | cut -d'"' -f4 + register: pre_audit_summary changed_when: false - - name: Pre Audit | Capture pre-audit result + - name: Pre Audit | Set Fact for audit summary ansible.builtin.set_fact: - pre_audit_summary: "{{ pre_audit.stdout | from_json | json_query(summary) }}" - vars: - summary: summary."summary-line" + pre_audit_results: "{{ pre_audit_summary.stdout }}" - name: Pre Audit | Capture audit data if documentation format when: - audit_format == "documentation" block: - - name: Pre Audit | Capture data {{ pre_audit_outfile }} | documentation format - ansible.builtin.shell: "tail -2 {{ pre_audit_outfile }}" - register: pre_audit + - name: Pre Audit | Capture audit data if documentation format + ansible.builtin.shell: tail -2 "{{ pre_audit_outfile }}" | tac | tr '\n' ' ' + register: pre_audit_summary changed_when: false - - name: Pre Audit | Capture pre-audit result | documentation format + - name: Pre Audit | Set Fact for audit summary ansible.builtin.set_fact: - pre_audit_summary: "{{ pre_audit.stdout_lines }}" + pre_audit_results: "{{ pre_audit_summary.stdout }}" - name: Audit_Only | Run Audit Only when: - audit_only - ansible.builtin.import_tasks: audit_only.yml + ansible.builtin.import_tasks: + file: audit_only.yml diff --git a/tasks/prelim.yml b/tasks/prelim.yml index 17891e5..6879596 100644 --- a/tasks/prelim.yml +++ b/tasks/prelim.yml @@ -1,20 +1,20 @@ --- -- name: PRELIM | set bootloader type +- name: PRELIM | Set bootloader type block: - name: "PRELIM | Check whether machine is UEFI-based" ansible.builtin.stat: path: /sys/firmware/efi register: rhel8_efi_boot - - name: "PRELIM | set fact if UEFI boot" + - name: "PRELIM | Set fact if UEFI boot" ansible.builtin.set_fact: rhel8stig_bootloader_path: /boot/efi/EFI/{{ ansible_distribution | lower }} rhel8stig_legacy_boot: false when: - rhel8_efi_boot.stat.exists - - name: "PRELIM | set fact if UEFI boot | Oracle Linux" + - name: "PRELIM | Set fact if UEFI boot | Oracle Linux" ansible.builtin.set_fact: rhel8stig_bootloader_path: /boot/efi/EFI/redhat rhel8stig_legacy_boot: false @@ -22,7 +22,7 @@ - rhel8_efi_boot.stat.exists - ansible_distribution == 'OracleLinux' - - name: "PRELIM | set if not UEFI boot" + - name: "PRELIM | Set if not UEFI boot" ansible.builtin.set_fact: rhel8stig_bootloader_path: /boot/grub2/ rhel8stig_legacy_boot: true @@ -57,7 +57,7 @@ tags: - always -- name: "PRELIM | RHEL-08-010400 | RHEL-08-020250 | RHEL-08-020290 | set sssd.conf location" +- name: "PRELIM | RHEL-08-010400 | RHEL-08-020250 | RHEL-08-020290 | Set sssd.conf location" block: - name: "PRELIM | RHEL-08-010400 | RHEL-08-020250 | RHEL-08-020290 | Get sssd.conf location" ansible.builtin.stat: @@ -79,7 +79,8 @@ - always - name: "PRELIM | Include audit specific variables" - ansible.builtin.include_vars: audit.yml + ansible.builtin.include_vars: + file: audit.yml when: - run_audit or audit_only - setup_audit @@ -88,7 +89,8 @@ - run_audit - name: "PRELIM | Include pre-remediation audit tasks" - ansible.builtin.import_tasks: pre_remediation_audit.yml + ansible.builtin.import_tasks: + file: pre_remediation_audit.yml when: - run_audit or audit_only - setup_audit @@ -103,7 +105,13 @@ check_mode: false register: rhel8stig_boot_part - - name: "PRELIM | RHEL-08-010020 | crypto-policies-scripts package for FIPS" + - name: "PRELIM | RHEL-08-010020 | Check if /boot or /boot/efi reside on separate partitions | get UUID" + ansible.builtin.shell: lsblk -f | grep -E "{{ rhel8stig_boot_part.stdout }}$" | awk '{ print $3 }' + changed_when: false + check_mode: false + register: rhel8stig_boot_uuid + + - name: "PRELIM | RHEL-08-010020 | Crypto-policies-scripts package for FIPS" ansible.builtin.package: name: crypto-policies-scripts state: present @@ -201,7 +209,7 @@ tags: - always -- name: "PRELIM | ensure cronie is available" +- name: "PRELIM | Ensure cronie is available" ansible.builtin.package: name: cronie when: diff --git a/vars/audit.yml b/vars/audit.yml index 2802b3e..1b19a56 100644 --- a/vars/audit.yml +++ b/vars/audit.yml @@ -34,7 +34,7 @@ audit_format: json audit_vars_path: "{{ audit_conf_dir }}/vars/{{ ansible_facts.hostname }}.yml" audit_results: | - The audit results are: {{ pre_audit_summary }} - {% if not audit_only %}The post remediation audit results are: {{ post_audit_summary }}{% endif %} + The{% if not audit_only %} pre remediation{% endif %} audit results are: {{ pre_audit_results }} + {% if not audit_only %}The post remediation audit results are: {{ post_audit_results }}{% endif %} Full breakdown can be found in {{ audit_log_dir }} diff --git a/vars/main.yml b/vars/main.yml index 92b4295..8398a98 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -1,6 +1,6 @@ --- -rhel8stig_min_ansible_version: 2.10.1 +rhel8stig_min_ansible_version: 2.11.1 rhel8stig_dconf_available: "{{ rhel8stig_gui or rhel8stig_dconf_audit.rc == 0 or rhel8stig_always_configure_dconf }}"