├── .ansible-lint ├── .gitattributes ├── .github └── workflows │ ├── devel_pipeline_validation.yml │ ├── main_pipeline_validation.yml │ └── update_galaxy.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .yamllint ├── CONTRIBUTING.rst ├── Changelog.md ├── LICENSE ├── Makefile ├── README.md ├── ansible.cfg ├── collections └── requirements.yml ├── defaults └── main.yml ├── filter_plugins └── filters.py ├── handlers └── main.yml ├── meta └── main.yml ├── requirements.txt ├── rules └── tag.py ├── site.yml ├── tasks ├── LE_audit_setup.yml ├── audit_homedirinifiles.yml ├── audit_only.yml ├── fetch_audit_output.yml ├── fix-cat1.yml ├── fix-cat2.yml ├── fix-cat3.yml ├── main.yml ├── parse_etc_passwd.yml ├── post_remediation_audit.yml ├── pre_remediation_audit.yml └── prelim.yml ├── templates ├── 01-banner-message.j2 ├── 01_users.j2 ├── aide.conf.j2 ├── ansible_vars_goss.yml.j2 ├── audit │ └── 99_auditd.rules.j2 ├── etc │ └── ansible │ │ └── compliance_facts.j2 ├── etc_default_grub.j2 └── resolv.conf.j2 ├── test_plugins ├── rhel8_stig_ansible_backport.py └── rhel8_stig_jinja_compat.py └── vars ├── AlmaLinux.yml ├── OracleLinux.yml ├── RedHat.yml ├── Rocky.yml ├── audit.yml ├── is_container.yml └── main.yml /.ansible-lint: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | parseable: true 4 | quiet: true 5 | skip_list: 6 | - 'schema' 7 | - 'no-changed-when' 8 | - 'var-spacing' 9 | - 'experimental' 10 | - 'name[play]' 11 | - 'name[casing]' 12 | - 'name[template]' 13 | - 'key-order[task]' 14 | - 'tag[no-duplicate]' 15 | - '204' 16 | - '305' 17 | - '303' 18 | - '403' 19 | - '306' 20 | - '602' 21 | - '208' 22 | - 'tag[no-duplicate]' 23 | use_default_rules: true 24 | rulesdir: 25 | - ./rules/ 26 | verbosity: 0 27 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # adding github settings to show correct language 2 | *.sh linguist-detectable=true 3 | *.yml linguist-detectable=true 4 | *.ps1 linguist-detectable=true 5 | *.j2 linguist-detectable=true 6 | *.md linguist-documentation 7 | -------------------------------------------------------------------------------- /.github/workflows/devel_pipeline_validation.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: Devel pipeline 4 | 5 | on: # yamllint disable-line rule:truthy 6 | pull_request_target: 7 | types: [opened, reopened, synchronize] 8 | branches: 9 | - devel 10 | - benchmark* 11 | paths: 12 | - '**.yml' 13 | - '**.sh' 14 | - '**.j2' 15 | - '**.ps1' 16 | - '**.cfg' 17 | # Allow manual running of workflow 18 | workflow_dispatch: 19 | 20 | # Allow permissions for AWS auth 21 | permissions: 22 | id-token: write 23 | contents: read 24 | pull-requests: read 25 | 26 | # A workflow run is made up of one or more jobs 27 | # that can run sequentially or in parallel 28 | jobs: 29 | # This will create messages for first time contributers and direct them to the Discord server 30 | welcome: 31 | runs-on: ubuntu-latest 32 | 33 | steps: 34 | - uses: actions/first-interaction@main 35 | with: 36 | repo-token: ${{ secrets.GITHUB_TOKEN }} 37 | pr-message: |- 38 | Congrats on opening your first pull request and thank you for taking the time to help improve Ansible-Lockdown! 39 | Please join in the conversation happening on the [Discord Server](https://www.lockdownenterprise.com/discord) as well. 40 | 41 | # This workflow contains a single job that tests the playbook 42 | playbook-test: 43 | # The type of runner that the job will run on 44 | runs-on: self-hosted 45 | env: 46 | ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }} 47 | # Imported as a variable by terraform 48 | TF_VAR_repository: ${{ github.event.repository.name }} 49 | AWS_REGION: "us-east-1" 50 | ANSIBLE_VERSION: ${{ vars.ANSIBLE_RUNNER_VERSION }} 51 | defaults: 52 | run: 53 | shell: bash 54 | working-directory: .github/workflows/github_linux_IaC 55 | # working-directory: .github/workflows 56 | 57 | steps: 58 | 59 | - name: Git clone the lockdown repository to test 60 | uses: actions/checkout@v4 61 | with: 62 | ref: ${{ github.event.pull_request.head.sha }} 63 | 64 | - name: If a variable for IAC_BRANCH is set use that branch 65 | working-directory: .github/workflows 66 | run: | 67 | if [ ${{ vars.IAC_BRANCH }} != '' ]; then 68 | echo "IAC_BRANCH=${{ vars.IAC_BRANCH }}" >> $GITHUB_ENV 69 | echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}" 70 | else 71 | echo IAC_BRANCH=main >> $GITHUB_ENV 72 | fi 73 | 74 | # Pull in terraform code for linux servers 75 | - name: Clone GitHub IaC plan 76 | uses: actions/checkout@v4 77 | with: 78 | repository: ansible-lockdown/github_linux_IaC 79 | path: .github/workflows/github_linux_IaC 80 | ref: ${{ env.IAC_BRANCH }} 81 | 82 | # Uses dedicated restricted role and policy to enable this only for this task 83 | # No credentials are part of github for AWS auth 84 | - name: configure aws credentials 85 | uses: aws-actions/configure-aws-credentials@main 86 | with: 87 | role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }} 88 | role-session-name: ${{ secrets.AWS_ROLE_SESSION }} 89 | aws-region: ${{ env.AWS_REGION }} 90 | 91 | - name: DEBUG - Show IaC files 92 | if: env.ENABLE_DEBUG == 'true' 93 | run: | 94 | echo "OSVAR = $OSVAR" 95 | echo "benchmark_type = $benchmark_type" 96 | echo "PRIVSUBNET_ID = $AWS_PRIVSUBNET_ID" 97 | echo "VPC_ID" = $AWS_VPC_SECGRP_ID" 98 | pwd 99 | ls 100 | env: 101 | # Imported from GitHub variables this is used to load the relevant OS.tfvars file 102 | OSVAR: ${{ vars.OSVAR }} 103 | benchmark_type: ${{ vars.BENCHMARK_TYPE }} 104 | PRIVSUBNET_ID: ${{ secrets.AWS_PRIVSUBNET_ID }} 105 | VPC_ID: ${{ secrets.AWS_VPC_SECGRP_ID }} 106 | 107 | - name: Tofu init 108 | id: init 109 | run: tofu init 110 | env: 111 | # Imported from GitHub variables this is used to load the relevant OS.tfvars file 112 | OSVAR: ${{ vars.OSVAR }} 113 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 114 | 115 | - name: Tofu validate 116 | id: validate 117 | run: tofu validate 118 | env: 119 | # Imported from GitHub variables this is used to load the relevant OS.tfvars file 120 | OSVAR: ${{ vars.OSVAR }} 121 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 122 | 123 | - name: Tofu apply 124 | id: apply 125 | env: 126 | OSVAR: ${{ vars.OSVAR }} 127 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 128 | TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} 129 | TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} 130 | run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false 131 | 132 | ## Debug Section 133 | - name: DEBUG - Show Ansible hostfile 134 | if: env.ENABLE_DEBUG == 'true' 135 | run: cat hosts.yml 136 | 137 | # Aws deployments taking a while to come up insert sleep or playbook fails 138 | 139 | - name: Sleep to allow system to come up 140 | run: sleep ${{ vars.BUILD_SLEEPTIME }} 141 | 142 | # Run the Ansible playbook 143 | - name: Run_Ansible_Playbook 144 | env: 145 | ANSIBLE_HOST_KEY_CHECKING: "false" 146 | ANSIBLE_DEPRECATION_WARNINGS: "false" 147 | run: | 148 | /opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml 149 | 150 | # Remove test system - User secrets to keep if necessary 151 | 152 | - name: Tofu Destroy 153 | if: always() && env.ENABLE_DEBUG == 'false' 154 | env: 155 | OSVAR: ${{ vars.OSVAR }} 156 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 157 | TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} 158 | TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} 159 | run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false 160 | -------------------------------------------------------------------------------- /.github/workflows/main_pipeline_validation.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: Main pipeline 4 | 5 | on: # yamllint disable-line rule:truthy 6 | pull_request_target: 7 | types: [opened, reopened, synchronize] 8 | branches: 9 | - main 10 | - latest 11 | paths: 12 | - '**.yml' 13 | - '**.sh' 14 | - '**.j2' 15 | - '**.ps1' 16 | - '**.cfg' 17 | 18 | # Allow permissions for AWS auth 19 | permissions: 20 | id-token: write 21 | contents: read 22 | pull-requests: read 23 | 24 | # A workflow run is made up of one or more jobs 25 | # that can run sequentially or in parallel 26 | jobs: 27 | 28 | # This workflow contains a single job that tests the playbook 29 | playbook-test: 30 | # The type of runner that the job will run on 31 | runs-on: self-hosted 32 | env: 33 | ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }} 34 | # Imported as a variable by terraform 35 | TF_VAR_repository: ${{ github.event.repository.name }} 36 | AWS_REGION : "us-east-1" 37 | ANSIBLE_VERSION: ${{ vars.ANSIBLE_RUNNER_VERSION }} 38 | defaults: 39 | run: 40 | shell: bash 41 | working-directory: .github/workflows/github_linux_IaC 42 | # working-directory: .github/workflows 43 | 44 | steps: 45 | 46 | - name: Git clone the lockdown repository to test 47 | uses: actions/checkout@v4 48 | with: 49 | ref: ${{ github.event.pull_request.head.sha }} 50 | 51 | - name: If a variable for IAC_BRANCH is set use that branch 52 | working-directory: .github/workflows 53 | run: | 54 | if [ ${{ vars.IAC_BRANCH }} != '' ]; then 55 | echo "IAC_BRANCH=${{ vars.IAC_BRANCH }}" >> $GITHUB_ENV 56 | echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}" 57 | else 58 | echo IAC_BRANCH=main >> $GITHUB_ENV 59 | fi 60 | 61 | # Pull in terraform code for linux servers 62 | - name: Clone GitHub IaC plan 63 | uses: actions/checkout@v4 64 | with: 65 | repository: ansible-lockdown/github_linux_IaC 66 | path: .github/workflows/github_linux_IaC 67 | ref: ${{ env.IAC_BRANCH }} 68 | 69 | # Uses dedicated restricted role and policy to enable this only for this task 70 | # No credentials are part of github for AWS auth 71 | - name: configure aws credentials 72 | uses: aws-actions/configure-aws-credentials@main 73 | with: 74 | role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }} 75 | role-session-name: ${{ secrets.AWS_ROLE_SESSION }} 76 | aws-region: ${{ env.AWS_REGION }} 77 | 78 | - name: DEBUG - Show IaC files 79 | if: env.ENABLE_DEBUG == 'true' 80 | run: | 81 | echo "OSVAR = $OSVAR" 82 | echo "benchmark_type = $benchmark_type" 83 | echo "PRIVSUBNET_ID = $AWS_PRIVSUBNET_ID" 84 | echo "VPC_ID" = $AWS_VPC_SECGRP_ID" 85 | pwd 86 | ls 87 | env: 88 | # Imported from GitHub variables this is used to load the relevant OS.tfvars file 89 | OSVAR: ${{ vars.OSVAR }} 90 | benchmark_type: ${{ vars.BENCHMARK_TYPE }} 91 | PRIVSUBNET_ID: ${{ secrets.AWS_PRIVSUBNET_ID }} 92 | VPC_ID: ${{ secrets.AWS_VPC_SECGRP_ID }} 93 | 94 | - name: Tofu init 95 | id: init 96 | run: tofu init 97 | env: 98 | # Imported from GitHub variables this is used to load the relevant OS.tfvars file 99 | OSVAR: ${{ vars.OSVAR }} 100 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 101 | 102 | - name: Tofu validate 103 | id: validate 104 | run: tofu validate 105 | env: 106 | # Imported from GitHub variables this is used to load the relevant OS.tfvars file 107 | OSVAR: ${{ vars.OSVAR }} 108 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 109 | 110 | - name: Tofu apply 111 | id: apply 112 | env: 113 | OSVAR: ${{ vars.OSVAR }} 114 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 115 | TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} 116 | TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} 117 | run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false 118 | 119 | ## Debug Section 120 | - name: DEBUG - Show Ansible hostfile 121 | if: env.ENABLE_DEBUG == 'true' 122 | run: cat hosts.yml 123 | 124 | # Aws deployments taking a while to come up insert sleep or playbook fails 125 | 126 | - name: Sleep to allow system to come up 127 | run: sleep ${{ vars.BUILD_SLEEPTIME }} 128 | 129 | # Run the Ansible playbook 130 | - name: Run_Ansible_Playbook 131 | env: 132 | ANSIBLE_HOST_KEY_CHECKING: "false" 133 | ANSIBLE_DEPRECATION_WARNINGS: "false" 134 | run: | 135 | /opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml 136 | 137 | # Remove test system - User secrets to keep if necessary 138 | 139 | - name: Tofu Destroy 140 | if: always() && env.ENABLE_DEBUG == 'false' 141 | env: 142 | OSVAR: ${{ vars.OSVAR }} 143 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 144 | TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} 145 | TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} 146 | run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false 147 | -------------------------------------------------------------------------------- /.github/workflows/update_galaxy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: update galaxy 4 | 5 | on: 6 | push: 7 | branches: 8 | - main 9 | jobs: 10 | update_role: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout repo 14 | uses: actions/checkout@v4 15 | 16 | - name: Action Ansible Galaxy Release ${{ github.ref_name }} 17 | uses: ansible-actions/ansible-galaxy-action@main 18 | with: 19 | galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | *.log 3 | *.retry 4 | .vagrant 5 | tests/*redhat-subscription 6 | tests/Dockerfile 7 | *.iso 8 | *.box 9 | packer_cache 10 | delete* 11 | ignore* 12 | # VSCode 13 | .vscode 14 | vagrant 15 | 16 | # Byte-compiled / optimized / DLL files 17 | __pycache__/ 18 | *.py[cod] 19 | *$py.class 20 | 21 | # DS_Store 22 | .DS_Store 23 | ._* 24 | 25 | # Linux Editors 26 | *~ 27 | \#*\# 28 | /.emacs.desktop 29 | /.emacs.desktop.lock 30 | .elc 31 | auto-save-list 32 | tramp 33 | .\#* 34 | *.swp 35 | *.swo 36 | rh-creds.env 37 | travis.env 38 | 39 | # Lockdown-specific 40 | benchparse/ 41 | *xccdf.xml 42 | *.retry 43 | 44 | # GitHub Action/Workflow files 45 | .github/ 46 | 47 | # ansible-lint 48 | .ansible/ 49 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ##### CI for use by github no need for action to be added 4 | ##### Inherited 5 | ci: 6 | autofix_prs: false 7 | skip: [detect-aws-credentials, ansible-lint ] 8 | 9 | repos: 10 | - repo: https://github.com/pre-commit/pre-commit-hooks 11 | rev: v5.0.0 12 | hooks: 13 | # Safety 14 | - id: detect-aws-credentials 15 | name: Detect AWS Credentials 16 | - id: detect-private-key 17 | name: Detect Private Keys 18 | 19 | # git checks 20 | - id: check-merge-conflict 21 | name: Check for merge conflicts 22 | - id: check-added-large-files 23 | name: Check for Large files 24 | - id: check-case-conflict 25 | name: Check case conflict 26 | 27 | # General checks 28 | - id: trailing-whitespace 29 | name: Trim Trailing Whitespace 30 | description: This hook trims trailing whitespace. 31 | entry: trailing-whitespace-fixer 32 | language: python 33 | types: [text] 34 | args: [--markdown-linebreak-ext=md] 35 | - id: end-of-file-fixer 36 | name: Ensure line at end of file 37 | 38 | # Scan for passwords 39 | - repo: https://github.com/Yelp/detect-secrets 40 | rev: v1.5.0 41 | hooks: 42 | - id: detect-secrets 43 | 44 | - repo: https://github.com/gitleaks/gitleaks 45 | rev: v8.26.0 46 | hooks: 47 | - id: gitleaks 48 | 49 | - repo: https://github.com/ansible-community/ansible-lint 50 | rev: v25.5.0 51 | hooks: 52 | - id: ansible-lint 53 | name: Ansible-lint 54 | description: This hook runs ansible-lint. 55 | entry: python3 -m ansiblelint --force-color site.yml -c .ansible-lint 56 | language: python 57 | # do not pass files to ansible-lint, see: 58 | # https://github.com/ansible/ansible-lint/issues/611 59 | pass_filenames: false 60 | always_run: true 61 | # additional_dependencies: 62 | # https://github.com/pre-commit/pre-commit/issues/1526 63 | # If you want to use specific version of ansible-core or ansible, feel 64 | # free to override `additional_dependencies` in your own hook config 65 | # file. 66 | # - ansible-core>=2.10.1 67 | 68 | - repo: https://github.com/adrienverge/yamllint.git 69 | rev: v1.37.1 # or higher tag 70 | hooks: 71 | - id: yamllint 72 | name: Check YAML Lint 73 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | ignore: | 5 | tests/ 6 | molecule/ 7 | .github/ 8 | .gitlab-ci.yml 9 | *molecule.yml 10 | 11 | rules: 12 | indentation: 13 | # Requiring 4 space indentation 14 | spaces: 4 15 | # Requiring consistent indentation within a file, either indented or not 16 | indent-sequences: consistent 17 | braces: 18 | max-spaces-inside: 1 19 | level: error 20 | brackets: 21 | max-spaces-inside: 1 22 | level: error 23 | empty-lines: 24 | max: 1 25 | line-length: disable 26 | key-duplicates: enable 27 | new-line-at-end-of-file: enable 28 | new-lines: 29 | type: unix 30 | trailing-spaces: enable 31 | truthy: 32 | allowed-values: ['true', 'false'] 33 | check-keys: true 34 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | Contributing to MindPoint Group Projects 2 | ======================================== 3 | 4 | Signing your contribution 5 | ------------------------- 6 | 7 | We've chosen to use the Developer's Certificate of Origin (DCO) method 8 | that is employed by the Linux Kernel Project, which provides a simple 9 | way to contribute to MindPoint Group projects. 10 | 11 | The process is to certify the below DCO 1.1 text 12 | :: 13 | 14 | Developer's Certificate of Origin 1.1 15 | 16 | By making a contribution to this project, I certify that: 17 | 18 | (a) The contribution was created in whole or in part by me and I 19 | have the right to submit it under the open source license 20 | indicated in the file; or 21 | 22 | (b) The contribution is based upon previous work that, to the best 23 | of my knowledge, is covered under an appropriate open source 24 | license and I have the right under that license to submit that 25 | work with modifications, whether created in whole or in part 26 | by me, under the same open source license (unless I am 27 | permitted to submit under a different license), as indicated 28 | in the file; or 29 | 30 | (c) The contribution was provided directly to me by some other 31 | person who certified (a), (b) or (c) and I have not modified 32 | it. 33 | 34 | (d) I understand and agree that this project and the contribution 35 | are public and that a record of the contribution (including all 36 | personal information I submit with it, including my sign-off) is 37 | maintained indefinitely and may be redistributed consistent with 38 | this project or the open source license(s) involved. 39 | :: 40 | 41 | Then, when it comes time to submit a contribution, include the 42 | following text in your contribution commit message: 43 | 44 | :: 45 | 46 | Signed-off-by: Joan Doe 47 | 48 | :: 49 | 50 | 51 | This message can be entered manually, or if you have configured git 52 | with the correct `user.name` and `user.email`, you can use the `-s` 53 | option to `git commit` to automatically include the signoff message. 54 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | # Changes to RHEL8STIG 2 | 3 | ## STIG v2r2 4 | 5 | RuleIDs updated for listed controls after changes in control 6 | 7 | - RHEL-08-010030 - moved from CAT2 to CAT1 control 8 | - RHEL-08-010130 - hashing round increase min from 5000 to 100000 9 | - RHEL-08-010290 - MAC reordered 10 | - RHEL-08-010291 - Ciphers reordered 11 | - RHEL-08-010292 - RuleID 12 | - RHEL-08-010680 - RuleID 13 | 14 | ## 4.0.0 STIG v2r1 15 | 16 | RuleIDs updated for all controls 17 | Nist Control ID associations added 18 | 19 | - RHEL-08-010350 - command updated 20 | - RHEL-08-010472 - Not Applicable if fips 21 | - RHEL-08-020035 - version 8.7+ 22 | - RHEL-08-020039 RHEL-08-020040 RHEL-08-020041 RHEL-08-020042, RHEL-08-020070 - TMUX removed 23 | - RHEL-08-020220, RHEL-08-020221 - remember not required for PAM 24 | - RHEL-08-020320 - Updated Check and Fix 25 | - RHEL-08-030603, RHEL-08-040139, RHEL-08-040140, RHEL-08-040141 - Rules updated Ok if no USB peripherals 26 | - RHEL-08-040284 27 | - RHEL-08-040370 28 | - RHEL-08-010001 - removed as not a NIST value 29 | 30 | Min OS version updated to 2.10 31 | 32 | workflow updates 33 | 34 | ## 3.3 STIG V1R14 35 | 36 | - #232 - thanks to @eday87 @BJSmithIEEE 37 | - #298 thanks to @mikefrompsu 38 | - #299 thanks to @cpu010100 39 | - thanks to @dglinder 40 | - #301 41 | - #302 42 | - ansible config update 43 | 44 | - Added gui discovery option 45 | updated ruleids 46 | 47 | - CAT I 48 | - RHEL-08-020330 - cat1 49 | - CAT II 50 | - RHEL-08-010040 51 | - RHEL-08-010070 52 | - RHEL-08-010200 53 | - RHEL-08-010201 54 | - RHEL-08-010423 55 | - RHEL-08-010520 56 | - RHEL-08-010521 57 | - RHEL-08-010522 58 | - RHEL-08-010550 59 | - RHEL-08-010830 60 | - RHEL-08-020350 61 | - RHEL-08-040161 62 | - RHEL-08-040340 63 | - RHEL-08-040341 64 | 65 | ## 3.3 - STIG V1R13 - 24th Jan 2024 66 | 67 | - updated audit variables 68 | - workflow updates 69 | - #277 thanks to @BJSmithIEEE 70 | - #278 thanks to @prestonSeaman2 71 | - #299 thanks to @derekbentson 72 | - removed dependency on jmespath 73 | - updated 010120 prelim and idempotency 74 | 75 | ## 3.2 - STIG V1R13 - 24th Jan 2024 76 | 77 | - Audit updated 78 | - moved audit into prelim 79 | - updates to audit logic for copy and archive options 80 | 81 | ruleid updated 82 | 83 | - 010001 84 | - 020250 85 | - 020290 86 | - 040090 87 | 88 | CAT II 89 | 90 | - 020035 - updated rule and added handler for logind restart 91 | - 040020 - /bin/false update and ruleid update 92 | - 040080 - /bin/false and ruleid 93 | - 040111 - /bin/false and ruleid 94 | 95 | CAT III 96 | 97 | - 040021 - /bin/false and ruleid 98 | - 040022 - /bin/false and ruleid 99 | - 040023 - /bin/false and ruleid 100 | - 040024 - /bin/false and ruleid 101 | - 040025 - /bin/false and ruleid 102 | - 040026 - /bin/false and ruleid 103 | 104 | ## 3.1 - STIG V1R12 - 25th Oct 2023 105 | 106 | ruleid updated 107 | 108 | - 010020 109 | - 010471 110 | - 030741 111 | - 030742 112 | - 040400 113 | 114 | - added SSH validation 115 | - added ansible_facts for variable usage 116 | 117 | - AUDIT 118 | - Audit_only ability now added to run standalone audit 119 | - audit_only: true 120 | - Related Audit repo updated to improve tests audit binary(goss updated to latest version) 121 | 122 | ## 3.0.3 - Stig V1R11 - 26th July 2023 123 | 124 | - updates to collections since galaxy updated 125 | - updates to audit 126 | 127 | - #229 thanks to @JacobBuskirk 128 | 129 | ## 3.0.2 - Stig V1R11 - 26th July 2023 130 | 131 | - workflow and pipeline updates 132 | - links updates in documentation 133 | - #222 thanks to @BJSmithIEEE 134 | - #226 thanks to @jmalpede 135 | - lint config updates 136 | - lint updates 137 | - precommit added and configured 138 | 139 | ### 3.0.1 - Stig V1R11 - 26th July 2023 140 | 141 | Issues: 142 | 143 | - [#207](https://github.com/ansible-lockdown/RHEL8-STIG/issues/207) 144 | - [#208](https://github.com/ansible-lockdown/RHEL8-STIG/issues/208) 145 | - [#209](https://github.com/ansible-lockdown/RHEL8-STIG/issues/209) 146 | - [#210](https://github.com/ansible-lockdown/RHEL8-STIG/issues/210) 147 | - [#211](https://github.com/ansible-lockdown/RHEL8-STIG/issues/211) 148 | - [#212](https://github.com/ansible-lockdown/RHEL8-STIG/issues/212) 149 | 150 | ### 3.0.0 151 | 152 | Controls updated 153 | 154 | - CAT2: 155 | - 010030 - ruleid 156 | - 010200 - ruleid 157 | - 010201 - ruleid 158 | - 010290 - ruleid and SSH MACS updated 159 | - 010291 - ruleid and SSH Ciphers updated 160 | - 010770 - ruleid 161 | - 020035 - new control idlesession timeout new var rhel_08_020035_idlesessiontimeout 162 | - 020041 - ruleid and tmux script update 163 | - 030690 - ruleid and protocol options added 164 | - 040159 - ruleid 165 | - 040160 - ruleid 166 | - 040342 - ruleid and SSH KEX algorithms updated 167 | 168 | - CAT3 169 | - 010471 - ruleid 170 | 171 | - audit variables updated, new version 172 | - tidied up the end of the playbook ordering with reboot taking place(if set and enabled) prior to audit now. 173 | 174 | ## 2.9.2 175 | 176 | - #216 check that sudo user has a password check improvement 177 | - thanks to manish on discord for highlighting this 178 | 179 | ## 2.9.1 180 | 181 | - Issue #204 address 182 | - tidy up of prelim 183 | - update to allow against container 184 | - vars/is_container.yml updated and aligned 185 | - prelim fqcn 186 | 187 | ## 2.9.0 Stig V1R10 27th April 2023 188 | 189 | - Added new controls 190 | - RHEL-08-10019 191 | - RHEL-08-10358 192 | - updated control IDs 193 | - RHEL-08-10360 194 | - RHEL-08-10540 195 | - RHEL-08-10541 196 | - RHEL-08-10544 197 | - RHEL-08-10800 198 | - RHEL-08-20040 199 | - RHEL-08-20100 200 | - RHEL-08-20101 201 | - RHEL-08-20102 202 | - RHEL-08-20103 203 | - RHEL-08-20220 204 | - RHEL-08-20221 205 | - RHEL-08-20270 206 | - RHEL-08-30070 207 | - RHEL-08-40150 208 | 209 | - OracleLinux tested and added 210 | 211 | ## Release 2.8.6 212 | 213 | - [#194](https://github.com/ansible-lockdown/RHEL8-STIG/issues/194) thanks to @JacobBuskirk 214 | - [#196](https://github.com/ansible-lockdown/RHEL8-STIG/issues/196) thanks to @jmalpede 215 | 216 | - [#195](https://github.com/ansible-lockdown/RHEL8-STIG/pull/195) thanks to PoundsOfFlesh 217 | - [#197](https://github.com/ansible-lockdown/RHEL8-STIG/pull/197) thanks to PoundsOfFlesh 218 | 219 | ## Release 2.8.5 220 | 221 | - updated to /var/log mount check 222 | - added commnets for /mnt and removeable media on Azure systems 223 | 224 | ## Release 2.8.4 225 | 226 | - ansible version updated to 2.10.1 minimum 227 | - updated to ansible user check for passwd rule 010380 228 | - thanks to discord community member PoundsOfFlesh 229 | - update readme layout and latest audit example 230 | - changed disruptive back to false to allow users to control the settings 231 | 232 | ## Release 2.8.3 233 | 234 | - improvements to openssh configs and seperated tasks 235 | 236 | ## Release 2.8.2 237 | 238 | - updates to pamd logic thanks to @JacobBuskirk for highlighting 239 | 240 | Also following issues/PRs 241 | 242 | - #168 243 | - #169 244 | - #170 245 | - #171 246 | - #172 247 | - #177 248 | - #178 249 | - #179 250 | - #180 251 | - #181 252 | 253 | ## Release 2.8.0 254 | 255 | - updates to workflow 256 | - ami 257 | - update to actions to latest versions 258 | - update_galaxy workflow added 259 | - README alignment 260 | - ansible.cfg added showing how tested 261 | - audit template updated 262 | - moved warnihg statements arounf for reboot 263 | 264 | - RULEID reference updated 265 | - 010510 rule no longer required 266 | - 010671 improvement 267 | - 020040 loop added 268 | - 040090 - var typo fixed 269 | - 040342 new control for FIP_KEX Algorithms 270 | - new FIPS_KEX_ALGO variable 271 | 272 | ## Release 2.7.0 273 | 274 | - lint updates 275 | - Benchmark 1.8 Updates 276 | - New RULEID for the following, plus additional notes if needed 277 | - CAT1 278 | - RHEL-08-010000 279 | - CAT2 280 | - RHEL-08-010040 281 | - RHEL-08-010090 282 | - RHEL-08-010200 - Updated keep alive count max to 1 283 | - RHEL-08-010201 284 | - RHEL-08-010360 285 | - RHEL-08-010372 - Updated to include find and remove for conflicting parameters 286 | - RHEL-08-010373 - Updated to include find and remove for conflicting parameters 287 | - RHEL-08-010373 - Updated to include find and remove for conflicting parameters 288 | - RHEL-08-010374 - Updated to include find and remove for conflicting parameters 289 | - RHEL-08-010375 - Updated to include find and remove for conflicting parameters 290 | - RHEL-08-010376 - Updated to include find and remove for conflicting parameters 291 | - RHEL-08-010383 292 | - RHEL-08-010384 293 | - RHEL-08-010430 - Updated to include find and remove for conflicting parameters 294 | - RHEL-08-010400 295 | - RHEL-08-010500 296 | - RHEL-08-010510 297 | - RHEL-08-010520 298 | - RHEL-08-010521 299 | - RHEL-08-010522 300 | - RHEL-08-010550 301 | - RHEL-08-010671 302 | - RHEL-08-010830 303 | - RHEL-08-020330 304 | - RHEL-08-020090 305 | - RHEL-08-020104 306 | - RHEL-08-020110 307 | - RHEL-08-020120 308 | - RHEL-08-020130 309 | - RHEL-08-020140 310 | - RHEL-08-020150 311 | - RHEL-08-020160 312 | - RHEL-08-020170 313 | - RHEL-08-020190 314 | - RHEL-08-020221 315 | - RHEL-08-020230 316 | - RHEL-08-010280 317 | - RHEL-08-020300 318 | - RHEL-08-020350 - Updated CCI 319 | - RHEL-08-020352 320 | - RHEL-08-040127 - Added tasks to deal with different versions of RHEL8 321 | - RHEL-08-040161 322 | - RHEL-08-040209 - Updated to include find and remove for conflicting parameters 323 | - RHEL-08-040210 - Updated to include find and remove for conflicting parameters 324 | - RHEL-08-040220 - Updated to include find and remove for conflicting parameters 325 | - RHEL-08-040230 - Updated to include find and remove for conflicting parameters 326 | - RHEL-08-040239 - Updated to include find and remove for conflicting parameters 327 | - RHEL-08-040240 - Updated to include find and remove for conflicting parameters 328 | - RHEL-08-040249 - Updated to include find and remove for conflicting parameters 329 | - RHEL-08-040250 - Updated to include find and remove for conflicting parameters 330 | - RHEL-08-040259 - Updated to included find and remove for conflicting parameters 331 | - RHEL-08-040260 - Updated to include find and remove for conflicting parameters 332 | - RHEL-08-040261 - Updated to include find and remove for conflicting parameters 333 | - RHEL-08-040262 - Updated to include find and remove for conflicting parameters 334 | - RHEL-08-040270 - Updated to include find and remove for conflicting parameters 335 | - RHEL-08-040279 - Updated to include find and remove for conflicting parameters 336 | - RHEL-08-040280 - Updated to include find and remove for conflicting parameters 337 | - RHEL-08-040281 - Updated to include find and remove for conflicting parameters 338 | - RHEL-08-040282 - Updated to include find and remove for conflicting parameters 339 | - RHEL-08-040283 - Updated to include find adn remove for conflicting parameters 340 | - RHEL-08-040284 - Updated to include find adn remove for conflicting parameters 341 | - RHEL-08-040285 - Updated to include find adn remove for conflicting parameters 342 | - RHEL-08-040286 - Updated to include find adn remove for conflicting parameters 343 | - RHEL-08-040340 344 | - RHEL-08-040341 345 | - RHEL-08-040400 - New control 346 | - CAT3 347 | - RHEL-08-020340 - Updated CCI 348 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Mindpoint Group - A Tyto Athene Company / Ansible Lockdown 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # TESTS 2 | 3 | all: yamllint 4 | 5 | yamllint: 6 | git ls-files "*.yml"|xargs yamllint 7 | 8 | requirements: 9 | @echo 'Python dependencies:' 10 | @cat requirements.txt 11 | pip install -r requirements.txt 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RHEL 8 DISA STIG 2 | 3 | ## Configure a RHEL8 based system to be complaint with Disa STIG 4 | 5 | This role is based on RHEL 8 DISA STIG: [Version 2, Rel 2 released on 30, Jan 2025](https://dl.dod.cyber.mil/wp-content/uploads/stigs/zip/U_RHEL_8_V2R2_STIG.zip). 6 | 7 | --- 8 | 9 | ![Org Stars](https://img.shields.io/github/stars/ansible-lockdown?label=Org%20Stars&style=social) 10 | ![Stars](https://img.shields.io/github/stars/ansible-lockdown/rhel8-stig?label=Repo%20Stars&style=social) 11 | ![Forks](https://img.shields.io/github/forks/ansible-lockdown/rhel8-stig?style=social) 12 | ![followers](https://img.shields.io/github/followers/ansible-lockdown?style=social) 13 | [![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/AnsibleLockdown.svg?style=social&label=Follow%20%40AnsibleLockdown)](https://twitter.com/AnsibleLockdown) 14 | 15 | ![Discord Badge](https://img.shields.io/discord/925818806838919229?logo=discord) 16 | 17 | ![Release Branch](https://img.shields.io/badge/Release%20Branch-Main-brightgreen) 18 | ![Release Tag](https://img.shields.io/github/v/release/ansible-lockdown/RHEL8-STIG) 19 | ![Release Date](https://img.shields.io/github/release-date/ansible-lockdown/RHEL8-STIG) 20 | 21 | [![Main Pipeline Status](https://github.com/ansible-lockdown/RHEL8-STIG/actions/workflows/main_pipeline_validation.yml/badge.svg?)](https://github.com/ansible-lockdown/RHEL8-STIG/actions/workflows/main_pipeline_validation.yml) 22 | 23 | [![Devel Pipeline Status](https://github.com/ansible-lockdown/RHEL8-STIG/actions/workflows/devel_pipeline_validation.yml/badge.svg?)](https://github.com/ansible-lockdown/RHEL8-STIG/actions/workflows/devel_pipeline_validation.yml) 24 | ![Devel Commits](https://img.shields.io/github/commit-activity/m/ansible-lockdown/RHEL8-STIG/devel?color=dark%20green&label=Devel%20Branch%20Commits) 25 | 26 | ![Issues Open](https://img.shields.io/github/issues-raw/ansible-lockdown/RHEL8-STIG?label=Open%20Issues) 27 | ![Issues Closed](https://img.shields.io/github/issues-closed-raw/ansible-lockdown/RHEL8-STIG?label=Closed%20Issues&&color=success) 28 | ![Pull Requests](https://img.shields.io/github/issues-pr/ansible-lockdown/RHEL8-STIG?label=Pull%20Requests) 29 | 30 | ![License](https://img.shields.io/github/license/ansible-lockdown/RHEL8-STIG?label=License) 31 | 32 | --- 33 | 34 | ## Looking for support? 35 | 36 | [Lockdown Enterprise](https://www.lockdownenterprise.com#GH_AL_RH8_stig) 37 | 38 | [Ansible support](https://www.mindpointgroup.com/cybersecurity-products/ansible-counselor#GH_AL_RH8_stig) 39 | 40 | ### Community 41 | 42 | On our [Discord Server](https://www.lockdownenterprise.com/discord) to ask questions, discuss features, or just chat with other Ansible-Lockdown users 43 | 44 | --- 45 | 46 | Configure a RHEL/Rocky 8 system to be DISA STIG compliant. 47 | Non-disruptive CAT I, CAT II, and CAT III findings will be corrected by default. 48 | Disruptive finding remediation can be enabled by setting `rhel8stig_disruption_high` to `true`. 49 | 50 | ## Updating 51 | 52 | Coming from a previous release. 53 | 54 | As with all releases and updates, It is suggested to test and align controls. 55 | This contains rewrites and ID reference changes as per STIG documentation. 56 | 57 | ## Auditing 58 | 59 | This can be turned on or off within the defaults/main.yml file with the variable run_audit. The value is false by default, please refer to the wiki for more details. The defaults file also populates the goss checks to check only the controls that have been enabled in the ansible role. 60 | 61 | This is a quick, very lightweight, check (where possible) of config compliance and live/running settings. 62 | 63 | A form of auditing has been developed, by using a small (12MB) go binary called [goss](https://github.com/goss-org/goss) along with the relevant configurations to check. Without the need for infrastructure or other tooling. 64 | This audit will not only check the config has the correct setting but aims to capture if it is running with that configuration also trying to remove [false positives](https://www.mindpointgroup.com/blog/is-compliance-scanning-still-relevant/) in the process. 65 | 66 | ## Documentation 67 | 68 | - [Read The Docs](https://ansible-lockdown.readthedocs.io/en/latest/) 69 | 70 | ## Requirements 71 | 72 | - RHEL/Rocky/AlmaLinux/OL 8 - Other versions are not supported. 73 | - Other OSs can be checked by changing the skip_os_check to true for testing purposes. 74 | - Access to download or add the goss binary and content to the system if using auditing. options are available on how to get the content to the system. 75 | 76 | ## Dependencies 77 | 78 | The following packages must be installed on the controlling host/host where ansible is executed: 79 | 80 | - python2-passlib (or just passlib, if using python3) 81 | - python-lxml 82 | 83 | Packages python(2)-passlib are required for tasks with custom filters or modules. These are all required on the controller host that executes Ansible. 84 | 85 | ## Role Variables 86 | 87 | This role is designed that the end user should not have to edit the tasks themselves. All customizing should be done via the defaults/main.yml file or with extra vars within the project, job, workflow, etc. 88 | 89 | ### Tags 90 | 91 | There are many tags available for added control precision. Each control has it's own set of tags noting the control number as well as what parts of the system that control addresses. 92 | 93 | Below is an example of the tag section from a control within this role. Using this example if you set your run to skip all controls with the tag ssh, this task will be skipped. The 94 | opposite can also happen where you run only controls tagged with ssh. 95 | 96 | ```sh 97 | tags: 98 | - RHEL-08-010050 99 | - ssh 100 | - dod_logon_banner 101 | ``` 102 | 103 | ### Example Audit Summary 104 | 105 | This is based on a vagrant image with selections enabled. e.g. No Gui or firewall. 106 | Note: More tests are run during audit as we check config and running state. 107 | 108 | ```sh 109 | ok: [rocky8_efi] => 110 | msg: 111 | - 'The pre remediation results are: Count: 804, Failed: 416, Duration: 6.488s.' 112 | - 'The post remediation results are: Count: 804, Failed: 28, Duration: 68.687s.' 113 | - Full breakdown can be found in /opt 114 | 115 | PLAY RECAP **************************************************************************************************************** 116 | rocky8_efi : ok=482 changed=269 unreachable=0 failed=0 skipped=207 rescued=0 ignored=0 117 | ``` 118 | 119 | ## Branches 120 | 121 | - **devel** - This is the default branch and the working development branch. Community pull requests will pull into this branch 122 | - **main** - This is the release branch 123 | - **reports** - This is a protected branch for our scoring reports, no code should ever go here 124 | - **gh_pages** - github pages 125 | - **all other branches** - Individual community member branches 126 | 127 | ## Containers - testing 128 | 129 | - system_is_container 130 | 131 | This is set to false by defaults/main.yml 132 | If discovered it is a container type or ansible_connection == docker it will convert to run to with with true. 133 | Some controls will skip is this is true as they are not applicable at all. Others runs a subset of controls found in vars/is_container.yml based on a vendor supplied un altered image. 134 | 135 | **NON altered vendor image.** 136 | 137 | - container_vars_file: is_container.yml 138 | 139 | This vars file runs controls are grouped into tags so if the container does later have ssh it could be re-enabled by loading an alternative vars file. 140 | 141 | ## Community Contribution 142 | 143 | We encourage you (the community) to contribute to this role. Please read the rules below. 144 | 145 | - Your work is done in your own individual branch. Make sure to Signed-off and GPG sign all commits you intend to merge. 146 | - All community Pull Requests are pulled into the devel branch 147 | - Pull Requests into devel will confirm your commits have a GPG signature, Signed-off, and a functional test before being approved 148 | - Once your changes are merged and a more detailed review is complete, an authorized member will merge your changes into the main branch for a new release. 149 | 150 | ## Pipeline Testing 151 | 152 | uses: 153 | 154 | - ansible-core 2.16 155 | - ansible collections - pulls in the latest version based on requirements file 156 | - runs the audit using the devel branch 157 | - This is an automated test that occurs on pull requests into devel 158 | 159 | ## Known Issues 160 | 161 | If adopting stig rule RHEL-08-040134 162 | 163 | This will affect cloud init as per [bug 1839899](https://bugs.launchpad.net/cloud-init/+bug/1839899) 164 | 165 | ## Support 166 | 167 | This is a community project at its core and will be managed as such. 168 | 169 | If you would are interested in dedicated support to assist or provide bespoke setups 170 | 171 | - [Ansible Counselor](https://www.mindpointgroup.com/products/ansible-counselor-on-demand-ansible-services-and-consulting/) 172 | - [Try us out](https://engage.mindpointgroup.com/try-ansible-counselor) 173 | 174 | ## Credits 175 | 176 | This repo originated from work done by [Sam Doran](https://github.com/samdoran/ansible-role-stig) 177 | 178 | ## Added Extras 179 | 180 | - makefile - this is there purely for testing and initial setup purposes. 181 | - [pre-commit](https://pre-commit.com) can be tested and can be run from within the directory 182 | 183 | ```sh 184 | pre-commit run 185 | ``` 186 | 187 | ## Credits and Thanks 188 | 189 | Massive thanks to the fantastic community and all its members. 190 | This includes a huge thanks and credit to the original authors and maintainers. 191 | 192 | Josh Springer, Daniel Shepherd, Bas Meijer, James Cassell, Mike Renfro, DFed, George Nalen, Mark Bolwell 193 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | host_key_checking=False 3 | display_skipped_hosts=True 4 | system_warnings=False 5 | command_warnings=False 6 | nocows=1 7 | retry_files_save_path=/dev/null 8 | pipelining=true 9 | 10 | # Use the YAML callback plugin. 11 | # stdout_callback = yaml 12 | # Use the stdout_callback when running ad-hoc commands. 13 | bin_ansible_callbacks = True 14 | 15 | [privilege_escalation] 16 | 17 | [paramiko_connection] 18 | record_host_keys=False 19 | 20 | [ssh_connection] 21 | transfer_method=scp 22 | ssh_args = -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPersist=60s 23 | 24 | [accelerate] 25 | 26 | [selinux] 27 | 28 | [colors] 29 | 30 | [diff] 31 | -------------------------------------------------------------------------------- /collections/requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | collections: 4 | - name: community.general 5 | source: https://github.com/ansible-collections/community.general 6 | type: git 7 | 8 | - name: community.crypto 9 | source: https://github.com/ansible-collections/community.crypto 10 | type: git 11 | 12 | - name: ansible.posix 13 | source: https://github.com/ansible-collections/ansible.posix 14 | type: git 15 | -------------------------------------------------------------------------------- /filter_plugins/filters.py: -------------------------------------------------------------------------------- 1 | try: 2 | import passlib.hash 3 | HAS_PASSLIB = True 4 | PASSLIB_VERSION = float(passlib.__version__[:3]) 5 | except ImportError as e: 6 | HAS_PASSLIB = False 7 | 8 | from ansible import errors 9 | 10 | 11 | def grub2_hash(password, salt=None, iterations=25000): 12 | # Build list of keyword arguments to pass into hash/encrypt method 13 | kwargs = dict() 14 | 15 | if salt: 16 | # passlib generates a random salt of 64 byte length by default (recommended) 17 | kwargs['salt'] = salt.encode() 18 | 19 | if iterations: 20 | # passlib does 25000 rounds (in version 1.7) by default (recommended or set to a higher value) 21 | kwargs['rounds'] = iterations 22 | 23 | # Make sure we have passlib and the correct version 24 | if not HAS_PASSLIB: 25 | raise errors.AnsibleFilterError('grub2_hash requires the passlib python module to generate password hashes') 26 | 27 | if PASSLIB_VERSION < 1.5: 28 | raise errors.AnsibleFilterError('passlib >= 1.5 is required and %s is installed' % PASSLIB_VERSION) 29 | 30 | elif PASSLIB_VERSION < 1.7: 31 | encrypted = passlib.hash.grub_pbkdf2_sha512.encrypt(password, **kwargs) 32 | 33 | else: 34 | encrypted = passlib.hash.grub_pbkdf2_sha512.using(**kwargs).hash(password) 35 | 36 | return encrypted 37 | 38 | 39 | class FilterModule(object): 40 | 41 | def filters(self): 42 | return { 43 | 'grub2_hash': grub2_hash 44 | } 45 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: change_requires_reboot 4 | ansible.builtin.set_fact: 5 | change_requires_reboot: true 6 | 7 | - name: systemctl daemon-reload 8 | ansible.builtin.systemd: 9 | daemon_reload: true 10 | when: 11 | - not system_is_container 12 | 13 | - name: Restart_systemdlogin 14 | ansible.builtin.systemd: 15 | name: systemd-logind 16 | state: restarted 17 | 18 | - name: sysctl system 19 | ansible.builtin.shell: sysctl --system 20 | when: "'procps-ng' in ansible_facts.packages" 21 | 22 | - name: restart sshd 23 | ansible.builtin.service: 24 | name: sshd 25 | state: restarted 26 | when: 27 | - rhel_08_040159 28 | - not rhel8stig_system_is_chroot 29 | - "'openssh-server' in ansible_facts.packages" 30 | - not change_requires_reboot 31 | 32 | - name: restart sssd 33 | ansible.builtin.service: 34 | name: sssd 35 | state: restarted 36 | when: 37 | - "'sssd' in ansible_facts.packages" 38 | 39 | - name: restart snmpd 40 | ansible.builtin.service: 41 | name: snmpd 42 | state: restarted 43 | when: 44 | - not rhel8stig_system_is_chroot 45 | - not change_requires_reboot 46 | 47 | - name: restart rngd 48 | ansible.builtin.service: 49 | name: rngd.service 50 | state: restarted 51 | when: 52 | - rhel_08_010471 53 | 54 | - name: restart rsyslog 55 | ansible.builtin.service: 56 | name: rsyslog 57 | state: restarted 58 | when: 59 | - rhel_08_010561 60 | 61 | - name: restart firewalld 62 | ansible.builtin.service: 63 | name: firewalld 64 | state: restarted 65 | when: rhel_08_040101 66 | 67 | - name: restart fapolicyd 68 | ansible.builtin.service: 69 | name: fapolicyd 70 | state: restarted 71 | when: rhel_08_040136 72 | 73 | - name: generate fapolicyd rules 74 | ansible.builtin.shell: fagenrules --load 75 | when: rhel_08_040137_rules_dir.stat.exists 76 | 77 | - name: restart usbguard 78 | ansible.builtin.service: 79 | name: usbguard 80 | state: restarted 81 | when: rhel_08_040141 82 | 83 | - name: confirm grub2 user cfg 84 | ansible.builtin.stat: 85 | path: "/etc/grub.d/01_users" 86 | changed_when: rhel8stig_grub2_user_cfg.stat.exists 87 | register: rhel8stig_grub2_user_cfg 88 | notify: make grub2 config 89 | 90 | - name: make grub2 config 91 | ansible.builtin.shell: /usr/sbin/grub2-mkconfig --output={{ rhel8stig_bootloader_path }}/grub.cfg 92 | when: 93 | - rhel8stig_grub2_user_cfg.stat.exists 94 | - not rhel8stig_skip_for_travis 95 | - not system_is_container 96 | 97 | - name: copy grub2 config to BIOS/UEFI to satisfy benchmark 98 | listen: make grub2 config 99 | ansible.builtin.copy: 100 | src: "{{ rhel8stig_bootloader_path }}/grub.cfg" 101 | dest: "{{ rhel8stig_bootloader_path }}/grub.cfg" 102 | remote_src: true 103 | owner: root 104 | group: root 105 | mode: 'u+x,go-w' 106 | when: 107 | - rhel8stig_grub2_user_cfg.stat.exists 108 | - rhel8stig_workaround_for_disa_benchmark 109 | - not rhel8stig_skip_for_travis 110 | - not system_is_container 111 | 112 | - name: "restart {{ rhel8stig_time_service }}" 113 | ansible.builtin.service: 114 | name: "{{ rhel8stig_time_service }}" 115 | state: restarted 116 | when: 117 | - not rhel8stig_skip_for_travis 118 | - not rhel8stig_system_is_chroot 119 | - not system_is_container 120 | - not change_requires_reboot 121 | 122 | - name: update auditd 123 | ansible.builtin.template: 124 | src: audit/99_auditd.rules.j2 125 | dest: /etc/audit/rules.d/99_auditd.rules 126 | owner: root 127 | group: root 128 | mode: 'u-x,go-rwx' 129 | notify: restart auditd 130 | 131 | - name: restart auditd 132 | ansible.builtin.shell: /usr/sbin/service auditd restart 133 | when: 134 | - not rhel8stig_skip_for_travis 135 | - not rhel8stig_system_is_chroot 136 | - not system_is_container 137 | - not change_requires_reboot 138 | - rhel_08_030181 139 | 140 | - name: rebuild initramfs 141 | ansible.builtin.shell: dracut -f 142 | when: 143 | - not system_is_container 144 | 145 | - name: undo existing prelinking 146 | ansible.builtin.shell: prelink -ua 147 | 148 | - name: update running audit failure mode 149 | ansible.builtin.shell: auditctl -f {{ rhel8stig_auditd_failure_flag }} 150 | failed_when: false 151 | 152 | - name: clean up ssh host key 153 | ansible.builtin.file: 154 | path: "{{ item }}" 155 | state: absent 156 | with_items: 157 | - /etc/ssh/ssh_host_rsa_key 158 | - /etc/ssh/ssh_host_rsa_key.pub 159 | 160 | - name: init aide and wait 161 | ansible.builtin.shell: /usr/sbin/aide --init -B 'database_out=file:{{ rhel8stig_aide_temp_db_file }}' 162 | notify: move aide db 163 | 164 | - name: init aide 165 | ansible.builtin.shell: nohup /usr/sbin/aide --init -B 'database_out=file:{{ rhel8stig_aide_temp_db_file }}' > /dev/null & 166 | notify: move aide db 167 | 168 | - name: move aide db 169 | ansible.builtin.shell: "mv {{ rhel8stig_aide_temp_db_file }} {{ rhel8stig_aide_db_file }}" 170 | when: not rhel8stig_aide_db_status.stat.exists or rhel8stig_overwrite_aide_db 171 | 172 | - name: dconf update 173 | ansible.builtin.shell: dconf update 174 | when: 175 | - "'dconf' in ansible_facts.packages" 176 | - rhel8stig_always_configure_dconf 177 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: "MindPoint Group" 4 | description: "Apply the DISA RHEL 8 STIG" 5 | company: "MindPoint Group" 6 | license: MIT 7 | role_name: rhel8_stig 8 | namespace: mindpointgroup 9 | min_ansible_version: '2.11.1' 10 | platforms: 11 | - name: EL 12 | versions: 13 | - '8' 14 | galaxy_tags: 15 | - system 16 | - security 17 | - stig 18 | - hardening 19 | - benchmark 20 | - compliance 21 | - redhat 22 | - complianceascode 23 | - disa 24 | - rhel8 25 | - mindpoint 26 | collections: 27 | - community.general 28 | - community.crypto 29 | - ansible.posix 30 | dependencies: [] 31 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | passlib 2 | lxml 3 | jmespath 4 | yamllint 5 | -------------------------------------------------------------------------------- /rules/tag.py: -------------------------------------------------------------------------------- 1 | """Implementation of TagRule.""" 2 | 3 | from __future__ import annotations 4 | 5 | import re 6 | from typing import TYPE_CHECKING 7 | 8 | from ansiblelint.constants import LINE_NUMBER_KEY 9 | from ansiblelint.file_utils import Lintable 10 | from ansiblelint.rules import AnsibleLintRule, TransformMixin 11 | 12 | if TYPE_CHECKING: 13 | from ansiblelint.errors import MatchError 14 | from ansiblelint.utils import Task 15 | 16 | 17 | class TagRule(AnsibleLintRule, TransformMixin): 18 | """Rule for checking task tags.""" 19 | 20 | id = "tag" 21 | description = ( 22 | "All task tags should have distinct names" 23 | "and templates in tags should be avoided." 24 | ) 25 | severity = "MEDIUM" 26 | tags = ["idiom"] 27 | _re_templated = re.compile(r"^.*\{\{.*\}\}.*$") 28 | _ids = { 29 | "tag[no-duplicate]": "Tasks should not duplicate tags.", 30 | "tag[no-template]": "Tasks should not use Jinja templates in tags.", 31 | } 32 | 33 | def matchtask( 34 | self, 35 | task: Task, 36 | file: Lintable | None = None, 37 | ) -> list[MatchError]: 38 | results: list[MatchError] = [] 39 | if file and file.failed(): 40 | return results 41 | tags = task.get("tags") 42 | if tags: 43 | if len(tags) != len(set(tags)): 44 | results.append( 45 | self.create_matcherror( 46 | message="Tasks should not duplicate tags.", 47 | lineno=task[LINE_NUMBER_KEY], 48 | tag="tag[no-duplicate]", 49 | filename=file, 50 | ), 51 | ) 52 | for tag in tags: 53 | if self._re_templated.match(tag): 54 | results.append( 55 | self.create_matcherror( 56 | message="Tasks should not use Jinja templates in tags.", 57 | lineno=task[LINE_NUMBER_KEY], 58 | tag="tag[no-template]", 59 | filename=file, 60 | ), 61 | ) 62 | break 63 | return results 64 | -------------------------------------------------------------------------------- /site.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Run RHEL8 STiG hardening 4 | hosts: "{{ hosts | default('all') }}" 5 | become: true 6 | 7 | roles: 8 | - role: "{{ playbook_dir }}" 9 | -------------------------------------------------------------------------------- /tasks/LE_audit_setup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Pre Audit Setup | Set audit package name 4 | block: 5 | - name: Pre Audit Setup | Set audit package name | 64bit 6 | ansible.builtin.set_fact: 7 | audit_pkg_arch_name: AMD64 8 | when: ansible_facts.machine == "x86_64" 9 | 10 | - name: Pre Audit Setup | Set audit package name | ARM64 11 | ansible.builtin.set_fact: 12 | audit_pkg_arch_name: ARM64 13 | when: ansible_facts.machine == "arm64" 14 | 15 | - name: Pre Audit Setup | Download audit binary 16 | ansible.builtin.get_url: 17 | url: "{{ audit_bin_url }}{{ audit_pkg_arch_name }}" 18 | dest: "{{ audit_bin }}" 19 | owner: root 20 | group: root 21 | checksum: "{{ audit_bin_version[audit_pkg_arch_name + '_checksum'] }}" 22 | mode: '0555' 23 | when: 24 | - get_audit_binary_method == 'download' 25 | 26 | - name: Pre Audit Setup | Copy audit binary 27 | ansible.builtin.copy: 28 | src: "{{ audit_bin_copy_location }}" 29 | dest: "{{ audit_bin }}" 30 | mode: '0555' 31 | owner: root 32 | group: root 33 | when: 34 | - get_audit_binary_method == 'copy' 35 | -------------------------------------------------------------------------------- /tasks/audit_homedirinifiles.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "MEDIUM | RHEL-08-010660 | AUDIT | Local RHEL 8 initialization files must not execute world-writable programs." 3 | ansible.builtin.debug: 4 | msg: "You will need to audit {{ ini_item }} for reference to {{ item }}, which has been found with world-writable permissions. Those permissions will be changed in the next task to 0755." 5 | failed_when: false 6 | changed_when: false 7 | with_items: "{{ rhel_08_020730_perms_results.stdout_lines }}" 8 | when: 9 | - rhel8stig_disruption_high 10 | - rhel_08_010660 11 | - rhel_08_010660_perms_results.stdout_lines is defined 12 | tags: 13 | - RHEL-08-010660 14 | - complexity-high 15 | -------------------------------------------------------------------------------- /tasks/audit_only.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Audit_Only | Create local Directories for hosts 4 | ansible.builtin.file: 5 | mode: '0755' 6 | path: "{{ audit_capture_files_dir }}/{{ inventory_hostname }}" 7 | recurse: true 8 | state: directory 9 | when: fetch_audit_files 10 | delegate_to: localhost 11 | become: false 12 | 13 | - name: Audit_only | Show Audit Summary 14 | when: 15 | - audit_only 16 | ansible.builtin.debug: 17 | msg: "{{ audit_results.split('\n') }}" 18 | 19 | - name: Audit_only | Stop Playbook Audit Only selected 20 | when: 21 | - audit_only 22 | ansible.builtin.meta: end_play 23 | -------------------------------------------------------------------------------- /tasks/fetch_audit_output.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Stage to copy audit output to a centralised location 4 | 5 | - name: "FETCH_AUDIT_FILES | Fetch files and copy to controller" 6 | when: audit_output_collection_method == "fetch" 7 | ansible.builtin.fetch: 8 | src: "{{ item }}" 9 | dest: "{{ audit_output_destination }}" 10 | flat: true 11 | failed_when: false 12 | register: discovered_audit_fetch_state 13 | loop: 14 | - "{{ pre_audit_outfile }}" 15 | - "{{ post_audit_outfile }}" 16 | become: false 17 | 18 | # Added this option for continuity but could be changed by adjusting the variable audit_conf_dest 19 | # Allowing backup to one location 20 | - name: "FETCH_AUDIT_FILES | Copy files to location available to managed node" 21 | when: audit_output_collection_method == "copy" 22 | ansible.builtin.copy: 23 | src: "{{ item }}" 24 | dest: "{{ audit_output_destination }}" 25 | mode: 'u-x,go-wx' 26 | flat: true 27 | failed_when: false 28 | register: discovered_audit_copy_state 29 | loop: 30 | - "{{ pre_audit_outfile }}" 31 | - "{{ post_audit_outfile }}" 32 | 33 | - name: "FETCH_AUDIT_FILES | Fetch files and copy to controller | Warning if issues with fetch_audit_files" 34 | when: 35 | - (audit_output_collection_method == "fetch" and not discovered_audit_fetch_state.changed) or 36 | (audit_output_collection_method == "copy" and not discovered_audit_copy_state.changed) 37 | block: 38 | - name: "FETCH_AUDIT_FILES | Fetch files and copy to controller | Warning if issues with fetch_audit_files" 39 | ansible.builtin.debug: 40 | msg: "Warning!! Unable to write to localhost {{ audit_output_destination }} for audit file copy" 41 | -------------------------------------------------------------------------------- /tasks/fix-cat1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "HIGH | RHEL-08-010000 | AUDIT | The RHEL 8 must be a vendor-supported release." 4 | ansible.builtin.debug: 5 | msg: Minimum supported version of {{ ansible_distribution }} is {{ rhel8stig_min_supported_os_ver[ansible_distribution] }} 6 | changed_when: ansible_distribution_version is not version_compare(rhel8stig_min_supported_os_ver[ansible_distribution], '>=') 7 | when: 8 | - rhel_08_010000 9 | tags: 10 | - RHEL-08-010000 11 | - CAT1 12 | - CCI-000366 13 | - NIST800-53R4_CM-6 14 | - SRG-OS-000480-GPOS-00227 15 | - SV-230221r1017040_rule 16 | - V-230221 17 | 18 | - name: "HIGH | RHEL-08-010020 | PATCH | The Red Hat Enterprise Linux operating system must implement NIST FIPS-validated cryptography for the following: to provision digital signatures, to generate cryptographic hashes, and to protect data requiring data-at-rest protections in accordance with applicable federal laws, Executive Orders, directives, policies, regulations, and standards." 19 | block: 20 | - name: "HIGH | RHEL-08-010020 | PATCH | The Red Hat Enterprise Linux operating system must implement NIST FIPS-validated cryptography for the following: to provision digital signatures, to generate cryptographic hashes, and to protect data requiring data-at-rest protections in accordance with applicable federal laws, Executive Orders, directives, policies, regulations, and standards. | install FIPS" 21 | ansible.builtin.package: 22 | name: dracut-fips 23 | state: present 24 | notify: 25 | - rebuild initramfs 26 | - change_requires_reboot 27 | when: "'dracut-fips' not in ansible_facts.packages" 28 | 29 | - name: "HIGH | RHEL-08-010020 | PATCH | The Red Hat Enterprise Linux operating system must implement NIST FIPS-validated cryptography for the following: to provision digital signatures, to generate cryptographic hashes, and to protect data requiring data-at-rest protections in accordance with applicable federal laws, Executive Orders, directives, policies, regulations, and standards. | Enables FIPS mode on kernel" 30 | ansible.builtin.shell: fips-mode-setup --enable 31 | register: rhel_08_010020_kernel_fips_enable 32 | changed_when: rhel_08_010020_kernel_fips_enable.rc == 0 33 | notify: change_requires_reboot 34 | when: 35 | - ansible_proc_cmdline.fips is not defined or 36 | (ansible_proc_cmdline.fips is defined and ansible_proc_cmdline.fips != '1') 37 | 38 | - name: "HIGH | RHEL-08-010020 | PATCH | Disable prelinking." 39 | ansible.builtin.lineinfile: 40 | dest: /etc/sysconfig/prelink 41 | regexp: ^#?PRELINKING 42 | line: PRELINKING=no 43 | when: "'prelink' in ansible_facts.packages" 44 | notify: undo existing prelinking 45 | 46 | - name: "HIGH | RHEL-08-010020 | AUDIT | Check for GRUB_CMDLINE_LINUX in /etc/default/grub" 47 | ansible.builtin.shell: grep -P '^\s*GRUB_CMDLINE_LINUX=".*"$' /etc/default/grub 48 | changed_when: rhel_08_010020_default_grub_missing_audit.rc > 0 49 | failed_when: false 50 | check_mode: false 51 | register: rhel_08_010020_default_grub_missing_audit 52 | 53 | - name: "HIGH | RHEL-08-010020 | AUDIT | Parse sane GRUB_CMDLINE_LINUX from /proc/cmdline" 54 | ansible.builtin.shell: grep -oP ' ro \K.*?(?= ?LANG=)' /proc/cmdline 55 | check_mode: false 56 | changed_when: false 57 | failed_when: rhel_08_010020_grub_cmdline_linux_audit.rc > 1 58 | when: rhel_08_010020_default_grub_missing_audit is changed # noqa no-handler 59 | register: rhel_08_010020_grub_cmdline_linux_audit 60 | 61 | - name: "HIGH | RHEL-08-010020 | PATCH | Copy over a sane /etc/default/grub" 62 | ansible.builtin.template: 63 | src: etc_default_grub.j2 64 | dest: /etc/default/grub 65 | owner: root 66 | group: root 67 | mode: 'u-x,go-wx' 68 | vars: 69 | grub_cmdline_linux: "{{ rhel_08_010020_grub_cmdline_linux_audit.stdout }}" 70 | when: rhel_08_010020_default_grub_missing_audit is changed # noqa no-handler 71 | 72 | - name: "HIGH | RHEL-08-010020 | AUDIT | Verify fips kernel parameters in /etc/default/grub" 73 | ansible.builtin.shell: grep -P '^\s*GRUB_CMDLINE_LINUX=".*(?<=[" ])fips=1(?=[" ]).*"$' /etc/default/grub 74 | check_mode: false 75 | changed_when: false 76 | failed_when: rhel_08_010020_fips_kernel_set.rc not in [ 0, 1 ] 77 | register: rhel_08_010020_fips_kernel_set 78 | 79 | - name: "HIGH | RHEL-08-010020 | PATCH | fips=1 must be in /etc/default/grub" 80 | ansible.builtin.replace: 81 | path: /etc/default/grub 82 | regexp: "{{ rhel8stig_regexp_quoted_params }}" 83 | replace: "{{ rhel8stig_replace_quoted_params }}" 84 | vars: 85 | key: GRUB_CMDLINE_LINUX 86 | param: fips 87 | value: 1 88 | append: true # this is the default 89 | when: 90 | - not ansible_check_mode or 91 | rhel_08_010020_default_grub_missing_audit is not changed 92 | - rhel_08_010020_fips_kernel_set.stdout | length == 0 93 | notify: 94 | - confirm grub2 user cfg 95 | - change_requires_reboot 96 | 97 | - name: "HIGH | RHEL-08-010020 | AUDIT | Verify boot kernel parameters in /etc/default/grub" 98 | ansible.builtin.shell: grep -P '^\s*GRUB_CMDLINE_LINUX=".*(?<=[" ])boot=UUID={{ prelim_rhel8stig_boot_uuid.stdout }}(?=[" ]).*"$' /etc/default/grub 99 | check_mode: false 100 | changed_when: false 101 | failed_when: rhel_08_010020_boot_kernel_set.rc not in [ 0, 1 ] 102 | register: rhel_08_010020_boot_kernel_set 103 | 104 | - 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." 105 | ansible.builtin.replace: 106 | path: /etc/default/grub 107 | regexp: "{{ rhel8stig_regexp_quoted_params }}" 108 | replace: "{{ rhel8stig_replace_quoted_params }}" 109 | vars: 110 | query: "{{ prelim_rhel8stig_boot_part.stdout }}" 111 | key: GRUB_CMDLINE_LINUX # noqa: var-naming[no-reserved] 112 | param: boot 113 | value: UUID={{ prelim_rhel8stig_boot_uuid.stdout }} 114 | insert: true 115 | when: 116 | - prelim_rhel8stig_boot_part.stdout not in ['/', ''] 117 | - rhel_08_010020_boot_kernel_set.stdout | length == 0 118 | - not ansible_check_mode or 119 | rhel_08_010020_default_grub_missing_audit is not changed 120 | notify: confirm grub2 user cfg 121 | register: result 122 | 123 | - name: "HIGH | RHEL-08-010020 | AUDIT | Verify kernel parameters in /etc/default/grub" 124 | ansible.builtin.shell: grep -P '^\s*GRUB_CMDLINE_LINUX=".*(?<=[" ]){{ item | regex_escape }}(?=[" ]).*"$' /etc/default/grub 125 | check_mode: false 126 | with_items: 127 | - fips=1 128 | - boot=UUID={{ prelim_rhel8stig_boot_uuid.stdout }} 129 | register: rhel_08_010020_audit 130 | when: 131 | - not ansible_check_mode or 132 | rhel_08_010020_default_grub_missing_audit is not changed 133 | - "prelim_rhel8stig_boot_part.stdout not in ['/', ''] or 134 | 'boot=' not in item" 135 | changed_when: 136 | - ansible_check_mode 137 | - rhel_08_010020_audit is failed 138 | failed_when: 139 | - rhel_08_010020_audit is failed 140 | - not ansible_check_mode or 141 | rhel_08_010020_audit.rc > 1 142 | when: 143 | - rhel_08_010020 144 | tags: 145 | - RHEL-08-010020 146 | - CAT1 147 | - CCI-000068 148 | - NIST800-53R4_AC-17 149 | - SRG-OS-000033-GPOS-00014 150 | - SRG-OS-000125-GPOS-00065 151 | - SRG-OS-000396-GPOS-00176 152 | - SRG-OS-000423-GPOS-00187 153 | - SRG-OS-000478-GPOS-00223 154 | - SV-230223r1017042_rule 155 | - V-230223 156 | 157 | - name: "HIGH | RHEL-08-010030 | AUDIT | All RHEL 8 local disk partitions must implement cryptographic mechanisms to prevent unauthorized disclosure or modification of all information that requires at rest protection." 158 | block: 159 | - name: "HIGH | RHEL-08-010030 | AUDIT | All RHEL 8 local disk partitions must implement cryptographic mechanisms to prevent unauthorized disclosure or modification of all information that requires at rest protection. | Get partition layout" 160 | ansible.builtin.shell: lsblk 161 | changed_when: false 162 | failed_when: false 163 | register: rhel_08_010030_partition_layout 164 | 165 | - name: "HIGH | RHEL-08-010030 | AUDIT | All RHEL 8 local disk partitions must implement cryptographic mechanisms to prevent unauthorized disclosure or modification of all information that requires at rest protection. | Message out warning" 166 | ansible.builtin.debug: 167 | msg: 168 | - 'WARNING!! Below is the partition layout. Please run the "sudo more /etc/crypttab" command to confirm every persistent disk partition has an entry.' 169 | - "If partitions other than pseudo file systems (such as /var or /sys) this is a finding" 170 | - "{{ rhel_08_010030_partition_layout.stdout_lines }}" 171 | when: 172 | - rhel_08_010030 173 | tags: 174 | - RHEL-08-010030 175 | - CAT1 176 | - CCI-001199 177 | - NIST800-53R4_SC-28 178 | - SRG-OS-000185-GPOS-00079 179 | - SRG-OS-000404-GPOS-00183 180 | - SRG-OS-000405-GPOS-00184 181 | - SV-230224r1044787_rule 182 | - V-230224 183 | 184 | - name: "HIGH | RHEL-08-010121 | PATCH | The RHEL 8 operating system must not have accounts configured with blank or null passwords." 185 | block: 186 | - name: "HIGH | RHEL-08-010121 | AUDIT | The RHEL 8 operating system must not have accounts configured with blank or null passwords. | Get users with no pw set" 187 | ansible.builtin.shell: "awk -F: '!$2 {print $1}' /etc/shadow" 188 | changed_when: false 189 | failed_when: false 190 | check_mode: false 191 | register: rhel_08_010121_no_pw_users 192 | 193 | - name: "HIGH | RHEL-08-010121 | PATCH | The RHEL 8 operating system must not have accounts configured with blank or null passwords. | Warn on accounts with no passwords" 194 | ansible.builtin.debug: 195 | msg: 196 | - "Alert! You have users that are not using passwords. Please either set a password, lock, or remove the accounts below:" 197 | - "{{ rhel_08_010121_no_pw_users.stdout_lines }}" 198 | when: 199 | - rhel_08_010121_no_pw_users.stdout | length > 0 200 | - not rhel8stig_disruption_high 201 | 202 | - name: "HIGH | RHEL-08-010121 | PATCH | The RHEL 8 operating system must not have accounts configured with blank or null passwords. | Lock accounts with no passwords, disruptive" 203 | ansible.builtin.user: 204 | name: "{{ item }}" 205 | password_lock: true 206 | with_items: 207 | - "{{ rhel_08_010121_no_pw_users.stdout_lines }}" 208 | when: 209 | - rhel_08_010121_no_pw_users.stdout | length > 0 210 | - rhel8stig_disruption_high 211 | when: 212 | - rhel_08_010121 213 | tags: 214 | - RHEL-08-010121 215 | - CAT1 216 | - CCI-000366 217 | - NIST800-53R4_CM-6 218 | - SRG-OS-000480-GPOS-00227 219 | - SV-251706r1017359_rule 220 | - V-251706 221 | 222 | - name: | 223 | "HIGH | RHEL-08-010140 | PATCH | RHEL 8 operating systems booted with United Extensible Firmware Interface (UEFI) implemented must require authentication upon booting into single-user mode and maintenance." 224 | "HIGH | RHEL-08-010150 | PATCH | RHEL 8 operating systems booted with a BIOS must require authentication upon booting into single-user and maintenance modes." 225 | block: 226 | - name: | 227 | "HIGH | RHEL-08-010140 | PATCH | RHEL 8 operating systems booted with United Extensible Firmware Interface (UEFI) implemented must require authentication upon booting into single-user mode and maintenance. | Set Grub Password" 228 | "HIGH | RHEL-08-010150 | PATCH | RHEL 8 operating systems booted with a BIOS must require authentication upon booting into single-user and maintenance modes. | Set Grub Password" 229 | ansible.builtin.lineinfile: 230 | path: "{{ rhel8stig_bootloader_path }}/user.cfg" 231 | create: true 232 | regexp: ^GRUB2_PASSWORD= 233 | line: "GRUB2_PASSWORD={{ rhel8stig_bootloader_password_hash }}" 234 | owner: root 235 | group: root 236 | mode: 'u-x,g-wx,o-rwx' 237 | notify: confirm grub2 user cfg 238 | when: 239 | - not system_is_ec2 240 | - rhel_08_010140 or 241 | rhel_08_010150 242 | tags: 243 | - RHEL-08-010140 244 | - RHEL-08-010150 245 | - CAT1 246 | - CCI-000213 247 | - NIST800-53R4_AC-3 248 | - SRG-OS-000080-GPOS-00048 249 | - SV-230234r1017053_rule 250 | - SV-230235r1017054_rule 251 | - V-230234 252 | - V-230235 253 | - grub 254 | - bootloader 255 | 256 | - name: "HIGH | RHEL-08-010370 | PATCH | RHEL 8 must prevent the installation of software, patches, service packs, device drivers, or operating system components from a repository without verification they have been digitally signed using a certificate that is issued by a Certificate Authority (CA) that is recognized and approved by the organization." 257 | block: 258 | - name: "HIGH | RHEL-08-010370 | AUDIT | RHEL 8 must prevent the installation of software, patches, service packs, device drivers, or operating system components from a repository without verification they have been digitally signed using a certificate that is issued by a Certificate Authority (CA) that is recognized and approved by the organization. | Dnf Default" 259 | ansible.builtin.lineinfile: 260 | path: /etc/dnf/dnf.conf 261 | regexp: '^gpgcheck=' 262 | line: gpgcheck=1 263 | 264 | - name: "HIGH | RHEL-08-010370 | AUDIT | RHEL 8 must prevent the installation of software, patches, service packs, device drivers, or operating system components from a repository without verification they have been digitally signed using a certificate that is issued by a Certificate Authority (CA) that is recognized and approved by the organization. | Gather Repos" 265 | ansible.builtin.find: 266 | paths: /etc/yum.repos.d 267 | pattern: '*.repo' 268 | register: rhel_08_010370_repos_files_list_full 269 | 270 | - name: "HIGH | RHEL-08-010370 | AUDIT | RHEL 8 must prevent the installation of software, patches, service packs, device drivers, or operating system components from a repository without verification they have been digitally signed using a certificate that is issued by a Certificate Authority (CA) that is recognized and approved by the organization. | Flatten result" 271 | ansible.builtin.set_fact: 272 | rhel_08_010370_repos_files_list: "{{ rhel_08_010370_repos_files_list_full.files | map(attribute='path') | flatten }}" 273 | 274 | - name: "HIGH | RHEL-08-010370 | PATCH | RHEL 8 must prevent the installation of software, patches, service packs, device drivers, or operating system components from a repository without verification they have been digitally signed using a certificate that is issued by a Certificate Authority (CA) that is recognized and approved by the organization. | Set gpgcheck" 275 | ansible.builtin.lineinfile: 276 | path: "{{ item }}" 277 | regexp: '^gpgcheck' 278 | line: gpgcheck=1 279 | with_items: 280 | - "{{ rhel_08_010370_repos_files_list }}" 281 | when: 282 | - rhel_08_010370 283 | tags: 284 | - RHEL-08-010370 285 | - CAT1 286 | - CCI-001749 287 | - NIST800-53R4_CM-5 288 | - SRG-OS-000366-GPOS-00153 289 | - SV-230264r1017377_rule 290 | - V-230264 291 | - yum 292 | 293 | - name: "HIGH | RHEL-08-010371 | PATCH | RHEL 8 must prevent the installation of software, patches, service packs, device drivers, or operating system components of local packages without verification they have been digitally signed using a certificate that is issued by a Certificate Authority (CA) that is recognized and approved by the organization." 294 | ansible.builtin.lineinfile: 295 | path: /etc/dnf/dnf.conf 296 | regexp: '^localpkg_gpgcheck=' 297 | line: localpkg_gpgcheck=True 298 | when: 299 | - rhel_08_010371 300 | tags: 301 | - RHEL-08-010371 302 | - CAT1 303 | - CCI-001749 304 | - NIST800-53R4_CM-5 305 | - SRG-OS-000366-GPOS-00153 306 | - SV-230265r1017378_rule 307 | - V-230265 308 | - dnf 309 | 310 | - name: "HIGH | RHEL-08-010460 | PATCH | There must be no shosts.equiv files on the RHEL 8 operating system." 311 | ansible.builtin.file: 312 | path: /etc/ssh/shosts.equiv 313 | state: absent 314 | when: 315 | - rhel_08_010460 316 | tags: 317 | - RHEL-08-010460 318 | - CAT1 319 | - CCI-000366 320 | - NIST800-53R4_CM-6 321 | - SRG-OS-000480-GPOS-00227 322 | - SV-230283r1017094_rule 323 | - V-230283 324 | - shosts 325 | 326 | - name: "HIGH | RHEL-08-010470 | PATCH | There must be no .shosts files on the RHEL 8 operating system." 327 | block: 328 | - name: "HIGH | RHEL-08-010470 | PATCH | There must be no .shosts files on the RHEL 8 operating system. | Find .shosts files" 329 | ansible.builtin.shell: find / -name "*.shosts" 330 | changed_when: false 331 | failed_when: rhel_08_010470_shost_files.rc not in [ 0, 1 ] 332 | register: rhel_08_010470_shost_files 333 | 334 | - name: "HIGH | RHEL-08-010470 | PATCH | There must be no .shosts files on the RHEL 8 operating system. | Remove .shosts files" 335 | ansible.builtin.file: 336 | path: "{{ item }}" 337 | state: absent 338 | with_items: 339 | - "{{ rhel_08_010470_shost_files.stdout_lines }}" 340 | when: rhel_08_010470_shost_files.stdout | length > 0 341 | when: 342 | - rhel_08_010470 343 | tags: 344 | - RHEL-08-010470 345 | - CAT1 346 | - CCI-000366 347 | - NIST800-53R4_CM-6 348 | - SRG-OS-000480-GPOS-00227 349 | - SV-230284r1017095_rule 350 | - V-230284 351 | - shosts 352 | 353 | - name: "HIGH | RHEL-08-010820 | PATCH | Unattended or automatic logon via the RHEL 8 graphical user interface must not be allowed." 354 | ansible.builtin.lineinfile: 355 | path: /etc/gdm/custom.conf 356 | regexp: (?i)automaticloginenable 357 | line: AutomaticLoginEnable=false 358 | insertafter: '\[daemon\]' 359 | when: 360 | - rhel8stig_gui 361 | - rhel_08_010820 362 | tags: 363 | - RHEL-08-010820 364 | - CAT1 365 | - CCI-000366 366 | - NIST800-53R4_CM-6 367 | - SRG-OS-000480-GPOS-00229 368 | - SV-230329r1017140_rule 369 | - V-230329 370 | 371 | - name: "HIGH | RHEL-08-020330 | PATCH | RHEL 8 must not have accounts configured with blank or null passwords." 372 | ansible.builtin.lineinfile: 373 | path: /etc/ssh/sshd_config 374 | regexp: '(?i)^#?PermitEmptyPasswords' 375 | line: 'PermitEmptyPasswords no' 376 | validate: '/usr/sbin/sshd -T -f %s' 377 | notify: restart sshd 378 | when: 379 | - rhel_08_020330 380 | - rhel8stig_disruption_high 381 | - rhel8stig_ssh_required 382 | tags: 383 | - RHEL-08-020330 384 | - CAT1 385 | - CCI-000366 386 | - NIST800-53R4_CM-6 387 | - SRG-OS-000480-GPOS-00227 388 | - SV-230380r1017191_rule 389 | - V-230380 390 | - disruption_high 391 | 392 | - name: "HIGH | RHEL-08-020331 | PATCH | RHEL 8 must not allow blank or null passwords in the system-auth file." 393 | ansible.builtin.replace: 394 | path: /etc/pam.d/system-auth 395 | regexp: ' nullok' 396 | replace: '' 397 | when: 398 | - rhel_08_020331 399 | tags: 400 | - RHEL-08-020331 401 | - CAT1 402 | - CCI-000366 403 | - NIST800-53R4_CM-6 404 | - SRG-OS-000480-GPOS-00227 405 | - SV-268322r1017568_rule 406 | - V-244540 407 | 408 | - name: "HIGH | RHEL-08-020332 | PATCH | RHEL 8 must not allow blank or null passwords in the password-auth file." 409 | ansible.builtin.replace: 410 | path: /etc/pam.d/password-auth 411 | regexp: ' nullok' 412 | replace: '' 413 | when: 414 | - rhel_08_020332 415 | tags: 416 | - RHEL-08-020332 417 | - CAT1 418 | - CCI-000366 419 | - NIST800-53R4_CM-6 420 | - SRG-OS-000480-GPOS-00227 421 | - SV-244541r1017347_rule 422 | - V-244541 423 | 424 | - name: "HIGH | RHEL-08-040000 | PATCH | RHEL 8 must not have the telnet-server package installed." 425 | ansible.builtin.package: 426 | name: telnet-server 427 | state: absent 428 | when: 429 | - rhel_08_040000 430 | - "'telnet-server' in ansible_facts.packages" 431 | tags: 432 | - RHEL-08-040000 433 | - CAT1 434 | - CCI-000381 435 | - NIST800-53R4_CM-7 436 | - SRG-OS-000095-GPOS-00049 437 | - SV-230487r1017271_rule 438 | - V-230487 439 | 440 | - name: "HIGH | RHEL-08-040010 | PATCH | RHEL 8 must not have the rsh-server package installed." 441 | ansible.builtin.package: 442 | name: rsh-server 443 | state: absent 444 | when: 445 | - rhel_08_040010 446 | - "'rsh-server' in ansible_facts.packages" 447 | tags: 448 | - RHEL-08-040010 449 | - CAT1 450 | - CCI-000381 451 | - NIST800-53R4_CM-7 452 | - SRG-OS-000095-GPOS-00049 453 | - SV-230492r1017275_rule 454 | - V-230492 455 | 456 | - name: "HIGH | RHEL-08-040170 | PATCH | The x86 Ctrl-Alt-Delete key sequence must be disabled on RHEL 8." 457 | block: 458 | - name: "HIGH | RHEL-08-040170 | PATCH | The x86 Ctrl-Alt-Delete key sequence must be disabled on RHEL 8. | Mask ctrl-alt-del.target" 459 | ansible.builtin.systemd: 460 | name: ctrl-alt-del.target 461 | masked: true 462 | notify: systemctl daemon-reload 463 | 464 | - name: "HIGH | RHEL-08-040170 | PATCH | The x86 Ctrl-Alt-Delete key sequence must be disabled on RHEL 8. | Create symlink to /dev/null" 465 | ansible.builtin.file: 466 | src: /dev/null 467 | dest: /etc/systemd/system/ctrl-alt-del.target 468 | state: link 469 | notify: systemctl daemon-reload 470 | when: 471 | - rhel_08_040170 472 | tags: 473 | - RHEL-08-040170 474 | - CAT1 475 | - CCI-000366 476 | - NIST800-53R4_CM-6 477 | - SRG-OS-000480-GPOS-00227 478 | - SV-230529r1017289_rule 479 | - V-230529 480 | 481 | - name: "HIGH | RHEL-08-040171 | PATCH | The x86 Ctrl-Alt-Delete key sequence in RHEL 8 must be disabled if a graphical user interface is installed." 482 | block: 483 | - name: "HIGH | RHEL-08-040171 | PATCH | The x86 Ctrl-Alt-Delete key sequence in RHEL 8 must be disabled if a graphical user interface is installed. | Check for setting existing" 484 | ansible.builtin.shell: grep -sl logout /etc/dconf/db/local.d/* 485 | changed_when: false 486 | failed_when: false 487 | register: rhel_08_040171_logout_settings_status 488 | 489 | - name: "HIGH | RHEL-08-040171 | PATCH | The x86 Ctrl-Alt-Delete key sequence in RHEL 8 must be disabled if a graphical user interface is installed. | Add if missing" 490 | ansible.builtin.lineinfile: 491 | path: /etc/dconf/db/local.d/00-disable-CAD 492 | regexp: "{{ item.regexp }}" 493 | line: "{{ item.line }}" 494 | insertafter: "{{ item.insertafter }}" 495 | create: true 496 | owner: root 497 | group: root 498 | mode: 'u-x,go-wx' 499 | with_items: 500 | - { regexp: '^\[org/gnome/settings-daemon/plugins/media-keys\]', line: '[org/gnome/settings-daemon/plugins/media-keys]', insertafter: 'EOF' } 501 | - { regexp: 'logout=', line: "logout=''", insertafter: '\[org/gnome/settings-daemon/plugins/media-keys\]' } 502 | loop_control: 503 | label: "{{ item.line }}" 504 | when: rhel_08_040171_logout_settings_status.stdout | length == 0 505 | 506 | - name: "HIGH | RHEL-08-040171 | PATCH | The x86 Ctrl-Alt-Delete key sequence in RHEL 8 must be disabled if a graphical user interface is installed. | Edit if exists" 507 | ansible.builtin.replace: 508 | path: "{{ rhel_08_040171_logout_settings_status.stdout }}" 509 | regexp: '^[L|l]ogout=.*' 510 | replace: "logout=''" 511 | when: rhel_08_040171_logout_settings_status.stdout | length > 0 512 | when: 513 | - rhel_08_040171 514 | - "'gnome-desktop' in ansible_facts.packages or 'gnome-desktop3' in ansible_facts.packages" 515 | tags: 516 | - RHEL-08-040171 517 | - CAT1 518 | - CCI-000366 519 | - NIST800-53R4_CM-6 520 | - SRG-OS-000480-GPOS-00227 521 | - SV-230530r1017290_rule 522 | - V-230530 523 | 524 | - name: "HIGH | RHEL-08-040172 | PATCH | The systemd Ctrl-Alt-Delete burst key sequence in RHEL 8 must be disabled." 525 | ansible.builtin.lineinfile: 526 | path: /etc/systemd/system.conf 527 | regexp: '^CtrlAltDelBurstAction=|^#CtrlAltDelBurstAction=' 528 | line: CtrlAltDelBurstAction=none 529 | notify: systemctl daemon-reload 530 | when: 531 | - rhel_08_040172 532 | tags: 533 | - RHEL-08-040172 534 | - CAT1 535 | - CCI-000366 536 | - NIST800-53R4_CM-6 537 | - SRG-OS-000480-GPOS-00227 538 | - SV-230531r1017292_rule 539 | - V-230531 540 | 541 | - name: "HIGH | RHEL-08-040190 | PATCH | The Trivial File Transfer Protocol (TFTP) server package must not be installed if not required for RHEL 8 operational support." 542 | ansible.builtin.package: 543 | name: tftp-server 544 | state: absent 545 | when: 546 | - rhel_08_040190 547 | - "'tftp-server' in ansible_facts.packages" 548 | - not rhel8stig_tftp_required 549 | tags: 550 | - RHEL-08-040190 551 | - CAT1 552 | - CCI-000366 553 | - NIST800-53R4_CM-6 554 | - SRG-OS-000480-GPOS-00227 555 | - SV-230533r1017295_rule 556 | - V-230533 557 | - tftp 558 | 559 | - name: "HIGH | RHEL-08-040200 | PATCH | The root account must be the only account having unrestricted access to the RHEL 8 system." 560 | block: 561 | - name: "HIGH | RHEL-08-040200 | PATCH | The root account must be the only account having unrestricted access to the RHEL 8 system. | Get list of non-root accounts with UID of 0" 562 | ansible.builtin.shell: "cat /etc/passwd | awk -F: '($3 == 0 && $1 != \"root\") {i++;print $1 } END {exit i}'" 563 | changed_when: false 564 | failed_when: false 565 | register: rhel_08_040200_nonroot_uid 566 | 567 | - name: "HIGH | HIGH | RHEL-08-040200 | PATCH | The root account must be the only account having unrestricted access to the RHEL 8 system. | Lock non-root account with UID of 0" 568 | ansible.builtin.shell: "passwd -l {{ item }}" 569 | with_items: 570 | - "{{ rhel_08_040200_nonroot_uid.stdout_lines }}" 571 | when: rhel_08_040200_nonroot_uid.stdout | length > 0 572 | 573 | - name: "HIGH | RHEL-08-040200 | PATCH | The root account must be the only account having unrestricted access to the RHEL 8 system. | Display accounts that were locked" 574 | ansible.builtin.debug: 575 | msg: 576 | - "WARNING!! The following accounts were locked since they had UID of 0 and were not the root user" 577 | - " {{ rhel_08_040200_nonroot_uid.stdout_lines }}" 578 | when: rhel_08_040200_nonroot_uid.stdout | length > 0 579 | when: 580 | - rhel_08_040200 581 | - rhel8stig_disruption_high 582 | tags: 583 | - RHEL-08-040200 584 | - CAT1 585 | - CCI-000366 586 | - NIST800-53R4_CM-6 587 | - SRG-OS-000480-GPOS-00227 588 | - SV-230534r1017296_rule 589 | - V-230534 590 | - disruption_high 591 | 592 | - name: "HIGH | RHEL-08-040360 | PATCH | A File Transfer Protocol (FTP) server package must not be installed unless mission essential on RHEL 8." 593 | ansible.builtin.package: 594 | name: vsftpd 595 | state: absent 596 | when: 597 | - rhel_08_040360 598 | - "'vsftpd' in ansible_facts.packages" 599 | tags: 600 | - RHEL-08-040360 601 | - CAT1 602 | - CCI-000366 603 | - NIST800-53R4_CM-6 604 | - SRG-OS-000480-GPOS-00227 605 | - SV-230558r1017320_rule 606 | - V-230558 607 | - ftp 608 | -------------------------------------------------------------------------------- /tasks/fix-cat3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "LOW | RHEL-08-010171 | PATCH | RHEL 8 must have policycoreutils package installed." 4 | ansible.builtin.package: 5 | name: policycoreutils 6 | when: 7 | - rhel_08_010171 8 | tags: 9 | - RHEL-08-010171 10 | - CAT3 11 | - CCI-001084 12 | - NIST800-53R4_SC-3 13 | - SRG-OS-000134-GPOS-00068 14 | - SV-230241r1017060_rule 15 | - V-230241 16 | - policycoreutils 17 | 18 | - name: "LOW | RHEL-08-010292 | PATCH | RHEL 8 must ensure the SSH server uses strong entropy." 19 | ansible.builtin.lineinfile: 20 | path: /etc/sysconfig/sshd 21 | regexp: '^(#)?SSH_USE_STRONG_RNG=' 22 | line: SSH_USE_STRONG_RNG=32 23 | notify: restart sshd 24 | when: 25 | - rhel_08_010292 26 | - rhel8stig_ssh_required 27 | tags: 28 | - RHEL-08-010292 29 | - CAT3 30 | - CCI-000366 31 | - NIST800-53R4_CM-6 32 | - SRG-OS-000480-GPOS-00227 33 | - SV-230253r1044799_rule 34 | - V-230253 35 | - ssh 36 | 37 | - name: "LOW | RHEL-08-010375 | PATCH | RHEL 8 must restrict access to the kernel message buffer." 38 | block: 39 | - name: "LOW | RHEL-08-010375 | AUIDT | RHEL 8 must restrict access to the kernel message buffer. | Find conflicting instances" 40 | ansible.builtin.shell: grep -rs "kernel.dmesg_restrict = 0" /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf /usr/lib/sysctl.d/*.conf /lib/sysctl.d/*.conf /etc/sysctl.conf /etc/sysctl.d/*.conf | cut -d':' -f1 41 | changed_when: false 42 | failed_when: false 43 | register: rhel_08_010375_conflicting_settings 44 | 45 | - name: "LOW | RHEL-08-010375 | PATCH | RHEL 8 must restrict access to the kernel message buffer. | Remove conflicting instances" 46 | ansible.builtin.lineinfile: 47 | path: "{{ item }}" 48 | regexp: '^kernel.dmesg_restrict = 0' 49 | state: absent 50 | loop: "{{ rhel_08_010375_conflicting_settings.stdout_lines }}" 51 | when: rhel_08_010375_conflicting_settings.stdout | length > 0 52 | 53 | - name: "LOW | RHEL-08-010375 | PATCH | RHEL 8 must restrict access to the kernel message buffer." 54 | ansible.posix.sysctl: 55 | name: kernel.dmesg_restrict 56 | value: 1 57 | state: present 58 | reload: "{{ rhel8stig_sysctl_reload }}" 59 | sysctl_set: true 60 | sysctl_file: "{{ rhel8stig_sysctl_file }}" 61 | when: 62 | - rhel_08_010375 63 | tags: 64 | - RHEL-08-010375 65 | - CAT3 66 | - CCI-001090 67 | - NIST800-53R4_SC-4 68 | - SRG-OS-000138-GPOS-00069 69 | - SV-230269r1017087_rule 70 | - V-230269 71 | - sysctl 72 | 73 | - name: "LOW | RHEL-08-010376 | PATCH | RHEL 8 must prevent kernel profiling by unprivileged users." 74 | block: 75 | - name: "LOW | RHEL-08-010376 | AUDIT | RHEL 8 must prevent kernel profiling by unprivileged users. | Find conflicting instances" 76 | ansible.builtin.shell: grep -rs "kernel.perf_event_paranoid = [^2]" /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf /usr/lib/sysctl.d/*.conf /lib/sysctl.d/*.conf /etc/sysctl.conf /etc/sysctl.d/*.conf | cut -d':' -f1 77 | changed_when: false 78 | failed_when: false 79 | register: rhel_08_010376_conflicting_settings 80 | 81 | - name: "LOW | RHEL-08-010376 | PATCH | RHEL 8 must prevent kernel profiling by unprivileged users. | Remove conflicting instances" 82 | ansible.builtin.lineinfile: 83 | path: "{{ item }}" 84 | regexp: '^kernel.perf_event_paranoid = [^2]' 85 | state: absent 86 | loop: "{{ rhel_08_010376_conflicting_settings.stdout_lines }}" 87 | when: rhel_08_010376_conflicting_settings.stdout | length > 0 88 | 89 | - name: "LOW | RHEL-08-010376 | PATCH | RHEL 8 must prevent kernel profiling by unprivileged users." 90 | ansible.posix.sysctl: 91 | name: kernel.perf_event_paranoid 92 | value: 2 93 | state: present 94 | reload: "{{ rhel8stig_sysctl_reload }}" 95 | sysctl_set: true 96 | sysctl_file: "{{ rhel8stig_sysctl_file }}" 97 | when: 98 | - rhel_08_010376 99 | tags: 100 | - RHEL-08-010376 101 | - CAT3 102 | - CCI-001090 103 | - NIST800-53R4_SC-4 104 | - SRG-OS-000138-GPOS-00069 105 | - SV-230270r1017088_rule 106 | - V-230270 107 | - sysctl 108 | 109 | - name: "LOW | RHEL-08-010440 | PATCH | YUM must remove all software components after updated versions have been installed on RHEL 8." 110 | block: 111 | - name: "LOW | RHEL-08-010440 | PATCH | YUM must remove all software components after updated versions have been installed on RHEL 8. | Find .conf files" 112 | ansible.builtin.find: 113 | paths: /etc 114 | recurse: true 115 | file_type: any 116 | depth: 2 117 | patterns: 118 | - yum.conf 119 | - dnf.conf 120 | register: rhel_08_010440_package_confs 121 | 122 | - name: "LOW | RHEL-08-010440 | PATCH | YUM must remove all software components after updated versions have been installed on RHEL 8. | Set settings" 123 | ansible.builtin.lineinfile: 124 | path: "{{ item.path }}" 125 | regexp: '^.*clean_requirements_on_remove' 126 | line: 'clean_requirements_on_remove=True' 127 | with_items: 128 | - "{{ rhel_08_010440_package_confs.files }}" 129 | loop_control: 130 | label: "{{ item.path }}" 131 | when: 132 | - rhel_08_010440 133 | tags: 134 | - RHEL-08-010440 135 | - CAT3 136 | - CCI-002617 137 | - NIST800-53R4_SI-2 138 | - SRG-OS-000437-GPOS-00194 139 | - SV-230281r958936_rule 140 | - V-230281 141 | 142 | - name: | 143 | "LOW | RHEL-08-010471 | PATCH | RHEL 8 must enable the hardware random number generator entropy gatherer service. 144 | LOW | RHEL-08-010472 | PATCH | RHEL 8 must have the packages required to use the hardware random number generator entropy gatherer service" 145 | block: 146 | - name: "LOW | RHEL-08-010472 | PATCH | RHEL 8 must have the packages required to use the hardware random number generator entropy gatherer service" 147 | ansible.builtin.package: 148 | name: rng-tools 149 | state: present 150 | when: 151 | - rhel_08_010472 152 | - "'rng-tools' not in ansible_facts.packages" 153 | 154 | - name: "LOW | RHEL-08-010471 | PATCH | RHEL 8 must enable the hardware random number generator entropy gatherer service." 155 | ansible.builtin.systemd: 156 | name: rngd.service 157 | enabled: true 158 | notify: restart rngd 159 | when: 160 | - rhel_08_010472 161 | - rhel_08_010471 162 | 163 | when: 164 | - rhel_08_010471 or 165 | rhel_08_010472 166 | - not rhel_08_010020 or ansible_fips # Can't enable if FIPS 167 | tags: 168 | - RHEL-08-010471 169 | - RHEL-08-010472 170 | - CAT3 171 | - CCI-000366 172 | - NIST800-53R4_CM-6 173 | - SRG-OS-000480-GPOS-00227 174 | - SV-230285r1017096_rule 175 | - SV-244527r1017333_rule 176 | - V-230285 177 | - V-244527 178 | 179 | - name: "LOW | RHEL-08-010540 | AUDIT | The RHEL 8 must use a separate file system for /var." 180 | ansible.builtin.debug: 181 | msg: "WARNING!! /var is not mounted on a separate partition" 182 | changed_when: 183 | - rhel8stig_audit_complex 184 | when: 185 | - rhel_08_010540 186 | - rhel8stig_complex 187 | - ansible_mounts | selectattr('mount', 'match', '^/var$') | list | length == 0 188 | tags: 189 | - RHEL-08-010540 190 | - CAT3 191 | - CCI-000366 192 | - NIST800-53R4_CM-6 193 | - SRG-OS-000480-GPOS-00227 194 | - SV-230292r1017103_rule 195 | - V-230292 196 | - complexity-high 197 | - mounts 198 | - var 199 | 200 | - name: "LOW | RHEL-08-010541 | AUDIT | RHEL 8 must use a separate file system for /var/log." 201 | ansible.builtin.debug: 202 | msg: 203 | - "WARNING!! /var/log is not mounted on a separate partition" 204 | changed_when: 205 | - rhel8stig_audit_complex 206 | when: 207 | - rhel_08_010541 208 | - rhel8stig_complex 209 | - ansible_mounts | selectattr('mount', 'match', '^/var/log$') | list | length == 0 210 | tags: 211 | - RHEL-08-010541 212 | - CAT3 213 | - CCI-000366 214 | - NIST800-53R4_CM-6 215 | - SRG-OS-000480-GPOS-00227 216 | - SV-230293r1017104_rule 217 | - V-230293 218 | - complexity_high 219 | - mounts 220 | 221 | - name: "LOW | RHEL-08-010542 | AUDIT | The RHEL 8 must use a separate file system for the system audit data path." 222 | ansible.builtin.debug: 223 | msg: 224 | - "WARNING!! /var/log/audit is not mounted on a seperate partition" 225 | changed_when: 226 | - rhel8stig_audit_complex 227 | when: 228 | - rhel_08_010542 229 | - rhel8stig_complex 230 | - ansible_mounts | selectattr('mount', 'match', '^/var/log/audit$') | list | length == 0 231 | tags: 232 | - RHEL-08-010542 233 | - CAT3 234 | - CCI-000366 235 | - NIST800-53R4_CM-6 236 | - SRG-OS-000480-GPOS-00227 237 | - SV-230294r1017105_rule 238 | - V-230294 239 | - complexity_high 240 | - mounts 241 | - auditd 242 | 243 | - name: "LOW | RHEL-08-020024 | PATCH | RHEL 8 must limit the number of concurrent sessions to ten for all accounts and/or account types." 244 | ansible.builtin.lineinfile: 245 | path: /etc/security/limits.conf 246 | regexp: '^\* hard maxlogins' 247 | line: '* hard maxlogins {{ rhel8stig_maxlogins }}' 248 | insertbefore: '^# End of file' 249 | create: true 250 | owner: root 251 | group: root 252 | mode: 'u-x,go-wx' 253 | when: 254 | - rhel_08_020024 255 | tags: 256 | - RHEL-08-020024 257 | - CAT3 258 | - CCI-000054 259 | - NIST800-53R4_AC-10 260 | - SRG-OS-000027-GPOS-00008 261 | - SV-230346r1017159_rule 262 | - V-230346 263 | 264 | - name: "LOW | RHEL-08-020340 | PATCH | RHEL 8 must display the date and time of the last successful account logon upon logon." 265 | ansible.builtin.lineinfile: 266 | path: /etc/pam.d/postlogin 267 | regexp: 'session.*required.*pam_lastlog\.so.*showfailed' 268 | line: "session required pam_lastlog.so showfailed" 269 | insertbefore: BOF 270 | when: 271 | - rhel_08_020340 272 | tags: 273 | - RHEL-08-020340 274 | - CAT3 275 | - CCI-000052 276 | - NIST800-53R4_AC-9 277 | - SRG-OS-000480-GPOS-00227 278 | - SV-230381r991589_rule 279 | - V-230381 280 | 281 | - name: "LOW | RHEL-08-030063 | PATCH | RHEL 8 must resolve audit information before writing to disk." 282 | ansible.builtin.lineinfile: 283 | path: /etc/audit/auditd.conf 284 | regexp: '^log_format =' 285 | line: "log_format = ENRICHED" 286 | notify: restart auditd 287 | when: 288 | - rhel_08_030063 289 | tags: 290 | - RHEL-08-030063 291 | - CAT3 292 | - CCI-000366 293 | - NIST800-53R4_CM-6 294 | - SRG-OS-000480-GPOS-00227 295 | - SV-230395r1017201_rule 296 | - V-230395 297 | - auditd 298 | 299 | - name: "LOW | RHEL-08-030601 | PATCH | RHEL 8 must enable auditing of processes that start prior to the audit daemon." 300 | block: 301 | - name: "LOW | RHEL-08-030601 | AUDIT | RHEL 8 must enable auditing of processes that start prior to the audit daemon. | Get GRUB_CMDLINE_LINUX settings" 302 | ansible.builtin.shell: grep GRUB_CMDLINE_LINUX= /etc/default/grub | cut -f2 -d'"' 303 | changed_when: false 304 | failed_when: false 305 | register: rhel8stig_030601_grub_cmdline_linux 306 | 307 | - name: "LOW | RHEL-08-030601 | PATCH | RHEL 8 must enable auditing of processes that start prior to the audit daemon. | Set audit to 1 as active" 308 | ansible.builtin.shell: grubby --update-kernel=ALL --args="audit=1" 309 | when: (ansible_proc_cmdline.audit is defined and ansible_proc_cmdline.audit != '1') or 310 | (ansible_proc_cmdline.audit is not defined) 311 | 312 | - name: "LOW | RHEL-08-030601 | PATCH | RHEL 8 must enable auditing of processes that start prior to the audit daemon. | Set audit=1 for kernel updates if doesnt exist" 313 | ansible.builtin.lineinfile: 314 | path: /etc/default/grub 315 | regexp: '^GRUB_CMDLINE_LINUX=' 316 | line: 'GRUB_CMDLINE_LINUX="{{ rhel8stig_030601_grub_cmdline_linux.stdout }} audit=1"' 317 | when: '"audit=" not in rhel8stig_030601_grub_cmdline_linux.stdout' 318 | 319 | - name: "LOW | RHEL-08-030601 | PATCH | RHEL 8 must enable auditing of processes that start prior to the audit daemon. | Set audit=1 for kernel updates if exists" 320 | ansible.builtin.replace: 321 | path: /etc/default/grub 322 | regexp: 'audit=([^\s|"])+' 323 | replace: "audit=1" 324 | when: '"audit=" in rhel8stig_030601_grub_cmdline_linux.stdout' 325 | when: 326 | - rhel_08_030601 327 | tags: 328 | - RHEL-08-030601 329 | - CAT3 330 | - CCI-000169 331 | - NIST800-53R4_AU-12 332 | - SRG-OS-000062-GPOS-00031 333 | - SRG-OS-000037-GPOS-00015 334 | - SRG-OS-000042-GPOS-00020 335 | - SRG-OS-000392-GPOS-00172 336 | - SRG-OS-000462-GPOS-00206 337 | - SRG-OS-000471-GPOS-00215 338 | - SRG-OS-000473-GPOS-00218 339 | - SV-230468r1017260_rule 340 | - V-230468 341 | - grub 342 | 343 | - name: "LOW | RHEL-08-030602 | PATCH | RHEL 8 must allocate an audit_backlog_limit of sufficient size to capture processes that start prior to the audit daemon." 344 | block: 345 | - name: "LOW | RHEL-08-030602 | AUDIT | RHEL 8 must allocate an audit_backlog_limit of sufficient size to capture processes that start prior to the audit daemon. | Get GRUB_CMDLINE_LINUX settings" 346 | ansible.builtin.shell: grep GRUB_CMDLINE_LINUX= /etc/default/grub | cut -f2 -d'"' 347 | changed_when: false 348 | failed_when: false 349 | register: rhel8stig_030602_grub_cmdline_linux 350 | 351 | - name: "LOW | RHEL-08-030602 | PATCH | RHEL 8 must allocate an audit_backlog_limit of sufficient size to capture processes that start prior to the audit daemon. | set audit_backlog_limit active" 352 | ansible.builtin.shell: grubby --update-kernel=ALL --args="audit_backlog_limit=8192" 353 | when: (ansible_proc_cmdline.audit_backlog_limit is defined and ansible_proc_cmdline.audit_backlog_limit != '8192') or 354 | (ansible_proc_cmdline.audit_backlog_limit is not defined) 355 | 356 | - name: "LOW | RHEL-08-030602 | PATCH | RHEL 8 must allocate an audit_backlog_limit of sufficient size to capture processes that start prior to the audit daemon. | Set audit audit_backlog_limit for kernel updates if doesn't exist" 357 | ansible.builtin.lineinfile: 358 | path: /etc/default/grub 359 | regexp: '^GRUB_CMDLINE_LINUX=' 360 | line: 'GRUB_CMDLINE_LINUX="{{ rhel8stig_030602_grub_cmdline_linux.stdout }} audit_backlog_limit=8192"' 361 | when: '"audit_backlog_limit=" not in rhel8stig_030602_grub_cmdline_linux.stdout' 362 | 363 | - name: "LOW | RHEL-08-030602 | PATCH | RHEL 8 must allocate an audit_backlog_limit of sufficient size to capture processes that start prior to the audit daemon. | Set audit audit_backlog_limit for kernel updates if exists" 364 | ansible.builtin.replace: 365 | path: /etc/default/grub 366 | regexp: 'audit_backlog_limit=([^\s|"])+' 367 | replace: "audit_backlog_limit=8192" 368 | when: '"audit_backlog_limit=" in rhel8stig_030602_grub_cmdline_linux.stdout' 369 | when: 370 | - rhel_08_030602 371 | tags: 372 | - RHEL-08-030602 373 | - CAT3 374 | - CCI-001849 375 | - NIST800-53R4_AU-4 376 | - SRG-OS-000341-GPOS-00132 377 | - SV-230469r958752_rule 378 | - V-230469 379 | - grub 380 | - auditd 381 | 382 | - name: "LOW | RHEL-08-030603 | PATCH | RHEL 8 must enable Linux audit logging for the USBGuard daemon" 383 | ansible.builtin.lineinfile: 384 | path: /etc/usbguard/usbguard-daemon.conf 385 | regexp: '^AuditBackend=' 386 | line: "AuditBackend=LinuxAudit" 387 | create: true 388 | owner: root 389 | group: root 390 | mode: 'u-x,go-rwx' 391 | when: 392 | - rhel_08_030603 393 | tags: 394 | - RHEL-08-030603 395 | - CAT3 396 | - CCI-000169 397 | - NIST800-53R4_AU-12 398 | - SRG-OS-000062-GPOS-00031 399 | - SRG-OS-000471-GPOS-00215 400 | - SV-230470r1017261_rule 401 | - V-230470 402 | - usb 403 | 404 | - name: "LOW | RHEL-08-030741 | PATCH | RHEL 8 must disable the chrony daemon from acting as a server." 405 | ansible.builtin.lineinfile: 406 | path: /etc/chrony.conf 407 | regexp: '^port|#port' 408 | line: "port 0" 409 | when: 410 | - rhel_08_030741 411 | - "'chrony' in ansible_facts.packages" 412 | tags: 413 | - RHEL-08-030741 414 | - CAT3 415 | - CCI-000381 416 | - NIST800-53R4_CM-7 417 | - SRG-OS-000095-GPOS-00049 418 | - SV-230485r1017269_rule 419 | - V-230485 420 | - chrony 421 | 422 | - name: "LOW | RHEL-08-030742 | PATCH | RHEL 8 must disable network management of the chrony daemon." 423 | ansible.builtin.lineinfile: 424 | path: /etc/chrony.conf 425 | regexp: '^cmdport|#cmdport' 426 | line: "cmdport 0" 427 | when: 428 | - rhel_08_030742 429 | tags: 430 | - RHEL-08-030742 431 | - CAT3 432 | - CCI-000381 433 | - NIST800-53R4_CM-7 434 | - SRG-OS-000095-GPOS-00049 435 | - SV-230486r1017270_rule 436 | - V-230486 437 | - chrony 438 | 439 | - name: "LOW | RHEL-08-040004 | PATCH | RHEL 8 must enable mitigations against processor-based vulnerabilities." 440 | block: 441 | - name: "LOW | RHEL-08-040004 | PATCH | RHEL 8 must enable mitigations against processor-based vulnerabilities. | Set pti=on active" 442 | ansible.builtin.shell: grubby --update-kernel=ALL --args="pti=on" 443 | when: (ansible_proc_cmdline.pti is defined and ansible_proc_cmdline.pti != 'on') or 444 | (ansible_proc_cmdline.pti is not defined ) 445 | 446 | - name: "LOW | RHEL-08-040004 | AUDIT | RHEL 8 must enable mitigations against processor-based vulnerabilities. | Get GRUB_CMDLINE_LINUX settings" 447 | ansible.builtin.shell: grep GRUB_CMDLINE_LINUX= /etc/default/grub | cut -f2 -d'"' 448 | changed_when: false 449 | failed_when: false 450 | register: rhel8stig_040004_grub_cmdline_linux 451 | 452 | - name: "LOW | RHEL-08-040004 | PATCH | RHEL 8 must enable mitigations against processor-based vulnerabilities. | Set pti if doesn't exist" 453 | ansible.builtin.lineinfile: 454 | path: /etc/default/grub 455 | regexp: '^GRUB_CMDLINE_LINUX=' 456 | line: 'GRUB_CMDLINE_LINUX="{{ rhel8stig_040004_grub_cmdline_linux.stdout }} pti=on"' 457 | when: '"pti=on" not in rhel8stig_040004_grub_cmdline_linux.stdout' 458 | 459 | - name: "LOW | RHEL-08-040004 | PATCH | RHEL 8 must enable mitigations against processor-based vulnerabilities. | Set pti exists" 460 | ansible.builtin.replace: 461 | path: /etc/default/grub 462 | regexp: 'pti=([^\s|"])+' 463 | replace: "pti=on" 464 | when: '"pti=on" in rhel8stig_040004_grub_cmdline_linux.stdout' 465 | when: 466 | - rhel_08_040004 467 | tags: 468 | - RHEL-08-040004 469 | - CAT3 470 | - CCI-000381 471 | - NIST800-53R4_CM-7 472 | - SRG-OS-000095-GPOS-00049 473 | - SV-230491r1017274_rule 474 | - V-230491 475 | - grub 476 | 477 | - name: "LOW | RHEL-08-040021 | PATCH | RHEL 8 must disable the asynchronous transfer mode (ATM) protocol." 478 | ansible.builtin.lineinfile: 479 | path: /etc/modprobe.d/blacklist.conf 480 | regexp: "{{ item.regexp }}" 481 | line: "{{ item.line }}" 482 | insertafter: "{{ item.insertafter }}" 483 | create: true 484 | owner: root 485 | group: root 486 | mode: "{{ rhel8stig_blacklist_conf_file_perms }}" 487 | notify: change_requires_reboot 488 | with_items: 489 | - { regexp: '^install atm', line: 'install atm /bin/false', insertafter: 'EOF' } 490 | - { regexp: '^blacklist atm', line: 'blacklist atm', insertafter: '^install atm /bin/true' } 491 | when: 492 | - rhel_08_040021 493 | tags: 494 | - RHEL-08-040021 495 | - CAT3 496 | - CCI-000381 497 | - NIST800-53R4_CM-7 498 | - SRG-OS-000095-GPOS-00049 499 | - SV-230494r1017277_rule 500 | - V-230494 501 | - modprobe 502 | - atm 503 | 504 | - name: "LOW | RHEL-08-040022 | PATCH | RHEL 8 must disable the controller area network (CAN) protocol." 505 | ansible.builtin.lineinfile: 506 | path: /etc/modprobe.d/blacklist.conf 507 | regexp: "{{ item.regexp }}" 508 | line: "{{ item.line }}" 509 | insertafter: "{{ item.insertafter }}" 510 | create: true 511 | owner: root 512 | group: root 513 | mode: "{{ rhel8stig_blacklist_conf_file_perms }}" 514 | notify: change_requires_reboot 515 | with_items: 516 | - { regexp: '^install can', line: 'install can /bin/false', insertafter: 'EOF' } 517 | - { regexp: 'blacklist can', line: 'blacklist can', insertafter: '^install can /bin/true' } 518 | when: 519 | - rhel_08_040022 520 | tags: 521 | - RHEL-08-040022 522 | - CAT3 523 | - CCI-000381 524 | - NIST800-53R4_CM-7 525 | - SRG-OS-000095-GPOS-00049 526 | - SV-230495r1017278_rule 527 | - V-230495 528 | - modprobe 529 | - can 530 | 531 | - name: "LOW | RHEL-08-040023 | PATCH | RHEL 8 must disable the stream control transmission (SCTP) protocol." 532 | ansible.builtin.lineinfile: 533 | path: /etc/modprobe.d/blacklist.conf 534 | regexp: "{{ item.regexp }}" 535 | line: "{{ item.line }}" 536 | insertafter: "{{ item.insertafter }}" 537 | create: true 538 | owner: root 539 | group: root 540 | mode: "{{ rhel8stig_blacklist_conf_file_perms }}" 541 | notify: change_requires_reboot 542 | with_items: 543 | - { regexp: '^install sctp', line: 'install sctp /bin/false', insertafter: 'EOF' } 544 | - { regexp: '^blacklist sctp', line: 'blacklist sctp', insertafter: '^install sctp' } 545 | when: 546 | - rhel_08_040023 547 | tags: 548 | - RHEL-08-040023 549 | - CAT3 550 | - CCI-000381 551 | - NIST800-53R4_CM-7 552 | - SRG-OS-000095-GPOS-00049 553 | - V-230496r1017279_rule 554 | - V-230496 555 | - modprobe 556 | - sctp 557 | 558 | - name: "LOW | RHEL-08-040024 | PATCH | RHEL 8 must disable the transparent inter-process communication (TIPC) protocol." 559 | ansible.builtin.lineinfile: 560 | path: /etc/modprobe.d/blacklist.conf 561 | regexp: "{{ item.regexp }}" 562 | line: "{{ item.line }}" 563 | insertafter: "{{ item.insertafter }}" 564 | create: true 565 | owner: root 566 | group: root 567 | mode: "{{ rhel8stig_blacklist_conf_file_perms }}" 568 | notify: change_requires_reboot 569 | with_items: 570 | - { regexp: '^install tipc', line: 'install tipc /bin/false', insertafter: 'EOF' } 571 | - { regexp: '^blacklist tipc', line: 'blacklist tipc', insertafter: '^install tipc' } 572 | when: 573 | - rhel_08_040024 574 | tags: 575 | - RHEL-08-040024 576 | - CAT3 577 | - CCI-000381 578 | - NIST800-53R4_CM-7 579 | - SRG-OS-000095-GPOS-00049 580 | - SV-230497r1017280_rule 581 | - V-230497 582 | - modprobe 583 | - tipc 584 | 585 | - name: "LOW | RHEL-08-040025 | PATCH | RHEL 8 must disable mounting of cramfs." 586 | ansible.builtin.lineinfile: 587 | path: /etc/modprobe.d/blacklist.conf 588 | regexp: "{{ item.regexp }}" 589 | line: "{{ item.line }}" 590 | insertafter: "{{ item.insertafter }}" 591 | create: true 592 | owner: root 593 | group: root 594 | mode: "{{ rhel8stig_blacklist_conf_file_perms }}" 595 | notify: change_requires_reboot 596 | with_items: 597 | - { regexp: '^install cramfs', line: 'install cramfs /bin/false', insertafter: 'EOF' } 598 | - { regexp: 'blacklist cramfs', line: 'blacklist cramfs', insertafter: '^install cramfs' } 599 | when: 600 | - rhel_08_040025 601 | tags: 602 | - RHEL-08-040025 603 | - CAT3 604 | - CCI-000381 605 | - NIST800-53R4_CM-7 606 | - SRG-OS-000095-GPOS-00049 607 | - SV-230498r1017281_rule 608 | - V-230498 609 | - modprobe 610 | - cramfs 611 | 612 | - name: "LOW | RHEL-08-040026 | PATCH | RHEL 8 must disable IEEE 1394 (FireWire) Support." 613 | ansible.builtin.lineinfile: 614 | path: /etc/modprobe.d/blacklist.conf 615 | regexp: "{{ item.regexp }}" 616 | line: "{{ item.line }}" 617 | insertafter: "{{ item.insertafter }}" 618 | create: true 619 | owner: root 620 | group: root 621 | mode: "{{ rhel8stig_blacklist_conf_file_perms }}" 622 | notify: change_requires_reboot 623 | with_items: 624 | - { regexp: '^install firewire-core', line: 'install firewire-core /bin/false', insertafter: 'EOF' } 625 | - { regexp: '^blacklist firewire-core', line: 'blacklist firewire-core', insertafter: '^install firewire-core' } 626 | when: 627 | - rhel_08_040026 628 | tags: 629 | - RHEL-08-040026 630 | - CAT3 631 | - CCI-000381 632 | - NIST800-53R4_CM-7 633 | - SRG-OS-000095-GPOS-00049 634 | - SV-230499r1017282_rule 635 | - V-230499 636 | - modprobe 637 | - firewire 638 | 639 | - name: | 640 | "LOW | RHEL-08-040300 | PATCH | The RHEL 8 file integrity tool must be configured to verify extended attributes." 641 | "LOW | RHEL-08-040310 | PATCH | The RHEL 8 file integrity tool must be configured to verify Access Control Lists (ACLs)." 642 | ansible.builtin.template: 643 | src: aide.conf.j2 644 | dest: /etc/aide.conf 645 | owner: root 646 | group: root 647 | mode: 'u-x,go-rwx' 648 | when: 649 | - rhel_08_040300 650 | - rhel_08_040310 651 | tags: 652 | - CAT3 653 | - RHEL-08-040300 654 | - RHEL-08-040310 655 | - CCI-000366 656 | - NIST800-53R4_CM-6 657 | - SRG-OS-000480-GPOS-00227 658 | - SV-230551r1017313_rule 659 | - SV-230552r1017314_rule 660 | - V-230551 661 | - V-230552 662 | - aide 663 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Gather distribution info 4 | ansible.builtin.setup: 5 | gather_subset: distribution,!all,!min 6 | when: 7 | - ansible_facts.distribution is not defined 8 | tags: 9 | - always 10 | 11 | - name: Check OS version and family 12 | ansible.builtin.assert: 13 | that: (ansible_facts.distribution != 'CentOS' and ansible_facts.os_family == 'RedHat' or ansible_facts.os_family == "Rocky") and ansible_facts.distribution_major_version is version_compare('8', '==') 14 | fail_msg: "This role can only be run against RHEL/Rocky 8. {{ ansible_facts.distribution }} {{ ansible_facts.distribution_major_version }} is not supported." 15 | success_msg: "This role is running against a supported OS {{ ansible_facts.distribution }} {{ ansible_facts.distribution_major_version }}" 16 | when: 17 | - not skip_os_check 18 | tags: 19 | - always 20 | 21 | - name: Check ansible version 22 | ansible.builtin.assert: 23 | that: ansible_version.full is version_compare(rhel8stig_min_ansible_version, '>=') 24 | fail_msg: "You must use Ansible {{ rhel8stig_min_ansible_version }} or greater" 25 | success_msg: "This role is running a supported version of ansible {{ ansible_version.full }} >= {{ rhel8stig_min_ansible_version }}" 26 | tags: 27 | - always 28 | 29 | - name: Setup rules if container 30 | block: 31 | - name: Discover and set container variable if required 32 | ansible.builtin.set_fact: 33 | system_is_container: true 34 | 35 | - name: Load variable for container 36 | ansible.builtin.include_vars: 37 | file: "{{ container_vars_file }}" 38 | 39 | - name: Output if discovered is a container 40 | ansible.builtin.debug: 41 | msg: system has been discovered as a container 42 | when: 43 | - system_is_container 44 | when: 45 | - ansible_connection == 'docker' or 46 | ansible_facts.virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] 47 | tags: 48 | - container_discovery 49 | - always 50 | 51 | - name: "Check password set for connecting user" 52 | block: 53 | - name: Capture current password state of connecting user" 54 | ansible.builtin.shell: "grep {{ ansible_env.SUDO_USER }} /etc/shadow | awk -F: '{print $2}'" 55 | changed_when: false 56 | failed_when: false 57 | check_mode: false 58 | register: ansible_user_password_set 59 | 60 | - name: "Assert that password set for {{ ansible_env.SUDO_USER }} and account not locked" 61 | ansible.builtin.assert: 62 | that: ansible_user_password_set.stdout | length != 0 and ansible_user_password_set.stdout != "!!" 63 | fail_msg: "You have {{ sudo_password_rule }} enabled but the user = {{ ansible_env.SUDO_USER }} has no password set - It can break access" 64 | success_msg: "You have a password set for the {{ ansible_env.SUDO_USER }}" 65 | vars: 66 | sudo_password_rule: RHEL-08-010380 # pragma: allowlist secret 67 | when: 68 | - rhel_08_010380 69 | - ansible_env.SUDO_USER is defined 70 | - not system_is_ec2 71 | tags: 72 | - user_passwd 73 | 74 | - name: "Ensure superuser for grub does not match existing user" 75 | block: 76 | - name: "Ensure superuser for grub does not match existing user | capture users" 77 | ansible.builtin.shell: cat /etc/passwd | cut -d':' -f1 78 | changed_when: false 79 | failed_when: false 80 | check_mode: false 81 | register: rhel8stig_user_list 82 | 83 | - name: "Ensure superuser for grub does not match existing user" 84 | ansible.builtin.assert: 85 | that: rhel8stig_boot_superuser not in rhel8stig_user_list.stdout_lines 86 | fail_msg: "A unique name must be used for bootloader access user='{{ rhel8stig_boot_superuser }}' already exists refer to variable rhel8stig_boot_superuser" 87 | when: 88 | - rhel_08_010141 or 89 | rhel_08_010149 90 | tags: 91 | - RHEL-08-010141 92 | - RHEL-08-010149 93 | 94 | - name: Include OS specific variables 95 | ansible.builtin.include_vars: 96 | file: "{{ ansible_facts.distribution }}.yml" 97 | tags: 98 | - always 99 | 100 | - name: Check rhel8stig_bootloader_password_hash variable has been changed 101 | ansible.builtin.assert: 102 | that: rhel8stig_bootloader_password_hash != 'grub.pbkdf2.sha512.changethispassword' # pragma: allowlist secret 103 | msg: "This role will not be able to run single user password commands as rhel8stig_bootloader_password_hash variable has not been set" # pragma: allowlist secret 104 | 105 | when: 106 | - not system_is_ec2 107 | - not system_is_container 108 | - rhel_08_010140 or 109 | rhel_08_010150 110 | tags: 111 | - grub 112 | 113 | - name: Check if using resolv.conf template settings are changed 114 | ansible.builtin.assert: 115 | that: 116 | - rhel8_stig_resolv_domain != 'example.com' 117 | - rhel8_stig_resolv_search | length > 0 118 | msg: "You are set to change your resolv.conf file this can be very disruptive if not configured correctly" 119 | 120 | when: 121 | - rhel8_stig_use_resolv_template 122 | - rhel_08_010680 123 | tags: 124 | - always 125 | 126 | - name: Gather the package facts 127 | ansible.builtin.package_facts: 128 | manager: auto 129 | tags: 130 | - always 131 | 132 | - name: Include prelim tasks 133 | ansible.builtin.import_tasks: 134 | file: prelim.yml 135 | tags: 136 | - prelim_tasks 137 | - run_audit 138 | 139 | - name: Include CAT I patches 140 | ansible.builtin.import_tasks: 141 | file: fix-cat1.yml 142 | when: rhel8stig_cat1 143 | tags: 144 | - rhel8stig_cat1 145 | - high 146 | 147 | - name: Include CAT II patches 148 | ansible.builtin.import_tasks: 149 | file: fix-cat2.yml 150 | when: rhel8stig_cat2 151 | tags: 152 | - rhel8stig_cat2 153 | - medium 154 | 155 | - name: Include CAT III patches 156 | ansible.builtin.import_tasks: 157 | file: fix-cat3.yml 158 | when: rhel8stig_cat3 159 | tags: 160 | - rhel8stig_cat3 161 | - low 162 | 163 | - name: Flush handlers 164 | ansible.builtin.meta: flush_handlers 165 | 166 | - name: Reboot system 167 | block: 168 | - name: Reboot system if not skipped 169 | ansible.builtin.reboot: 170 | when: 171 | - change_requires_reboot 172 | - not rhel8stig_skip_reboot 173 | 174 | - name: Warning a reboot required but skip option set 175 | ansible.builtin.debug: 176 | msg: "Warning!! changes have been made that require a reboot to be implemented but skip reboot was set - Can affect compliance check results" 177 | changed_when: true 178 | when: 179 | - change_requires_reboot 180 | - rhel8stig_skip_reboot 181 | 182 | - name: Run post remediation audit 183 | ansible.builtin.import_tasks: 184 | file: post_remediation_audit.yml 185 | when: 186 | - run_audit 187 | tags: 188 | - run_audit 189 | 190 | - name: Add ansible file showing Benchmark and levels applied 191 | block: 192 | - name: Create ansible facts directory 193 | ansible.builtin.file: 194 | path: "{{ ansible_facts_path }}" 195 | state: directory 196 | owner: root 197 | group: root 198 | mode: 'u=rwx,go=rx' 199 | 200 | - name: Create ansible facts file 201 | ansible.builtin.template: 202 | src: etc/ansible/compliance_facts.j2 203 | dest: "{{ ansible_facts_path }}/compliance_facts.fact" 204 | owner: root 205 | group: root 206 | mode: "u-x,go-wx" 207 | when: create_benchmark_facts 208 | tags: 209 | - always 210 | - benchmark 211 | 212 | - name: Fetch audit files 213 | ansible.builtin.import_tasks: 214 | file: fetch_audit_output.yml 215 | when: 216 | - fetch_audit_output 217 | - run_audit 218 | tags: always 219 | 220 | - name: Show Audit Summary 221 | ansible.builtin.debug: 222 | msg: "{{ audit_results.split('\n') }}" 223 | when: 224 | - run_audit 225 | tags: 226 | - run_audit 227 | -------------------------------------------------------------------------------- /tasks/parse_etc_passwd.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PRELIM | {{ rhel8stig_passwd_tasks }} | Parse /etc/passwd" 3 | block: 4 | - name: "PRELIM | {{ rhel8stig_passwd_tasks }} | Parse /etc/passwd" 5 | ansible.builtin.shell: cat /etc/passwd 6 | changed_when: false 7 | check_mode: false 8 | register: rhel8stig_passwd_file_audit 9 | 10 | - name: "PRELIM | {{ rhel8stig_passwd_tasks }} | Split passwd entries" 11 | ansible.builtin.set_fact: 12 | rhel8stig_passwd: "{{ rhel8stig_passwd_file_audit.stdout_lines | map('regex_replace', ld_passwd_regex, ld_passwd_yaml) | map('from_yaml') | list }}" 13 | 14 | with_items: "{{ rhel8stig_passwd_file_audit.stdout_lines }}" 15 | vars: 16 | ld_passwd_regex: >- 17 | ^(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*) 18 | ld_passwd_yaml: | # pragma: allowlist secret 19 | id: >-4 20 | \g 21 | password: >-4 22 | \g 23 | uid: \g 24 | gid: \g 25 | gecos: >-4 26 | \g 27 | dir: >-4 28 | \g 29 | shell: >-4 30 | \g 31 | tags: 32 | - always 33 | -------------------------------------------------------------------------------- /tasks/post_remediation_audit.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Post Audit | Run post_remediation {{ benchmark }} audit 4 | ansible.builtin.shell: "{{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -o {{ post_audit_outfile }} -g \"{{ group_names }}\"" 5 | changed_when: true 6 | environment: 7 | AUDIT_BIN: "{{ audit_bin }}" 8 | AUDIT_CONTENT_LOCATION: "{{ audit_conf_dest | default('/opt') }}" 9 | AUDIT_FILE: goss.yml 10 | 11 | - name: Post Audit | ensure audit files readable by users 12 | ansible.builtin.file: 13 | path: "{{ item }}" 14 | mode: '0644' 15 | state: file 16 | loop: 17 | - "{{ post_audit_outfile }}" 18 | - "{{ pre_audit_outfile }}" 19 | 20 | - name: Post Audit | Capture audit data if json format 21 | when: 22 | - audit_format == "json" 23 | block: 24 | - name: Post Audit | Capture audit data if json format 25 | ansible.builtin.shell: grep -E '"summary-line.*Count:.*Failed' "{{ post_audit_outfile }}" | cut -d'"' -f4 26 | register: post_audit_summary 27 | changed_when: false 28 | 29 | - name: Post Audit | Set Fact for audit summary 30 | ansible.builtin.set_fact: 31 | post_audit_results: "{{ post_audit_summary.stdout }}" 32 | 33 | - name: Post Audit | Capture audit data if documentation format 34 | when: 35 | - audit_format == "documentation" 36 | block: 37 | - name: Post Audit | Capture audit data if documentation format 38 | ansible.builtin.shell: tail -2 "{{ post_audit_outfile }}" | tac | tr '\n' ' ' 39 | register: post_audit_summary 40 | changed_when: false 41 | 42 | - name: Post Audit | Set Fact for audit summary 43 | ansible.builtin.set_fact: 44 | post_audit_results: "{{ post_audit_summary.stdout }}" 45 | -------------------------------------------------------------------------------- /tasks/pre_remediation_audit.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Pre Audit Setup | Setup the LE audit 4 | when: 5 | - setup_audit 6 | tags: 7 | - setup_audit 8 | ansible.builtin.include_tasks: 9 | file: LE_audit_setup.yml 10 | 11 | - name: Pre Audit Setup | Ensure {{ audit_conf_dir }} exists 12 | ansible.builtin.file: 13 | path: "{{ audit_conf_dir }}" 14 | state: directory 15 | mode: '0755' 16 | 17 | - name: Pre Audit Setup | If using git for content set up 18 | when: 19 | - audit_content == 'git' 20 | block: 21 | - name: Pre Audit Setup | Install git 22 | ansible.builtin.package: 23 | name: git 24 | state: present 25 | 26 | - name: Pre Audit Setup | Retrieve audit content files from git 27 | ansible.builtin.git: 28 | repo: "{{ audit_file_git }}" 29 | dest: "{{ audit_conf_dir }}" 30 | version: "{{ audit_git_version }}" 31 | 32 | - name: Pre Audit Setup | Copy to audit content files to server 33 | when: 34 | - audit_content == 'copy' 35 | ansible.builtin.copy: 36 | src: "{{ audit_conf_source }}" 37 | dest: "{{ audit_conf_dest }}" 38 | mode: preserve 39 | 40 | - name: Pre Audit Setup | Unarchive audit content files on server 41 | when: 42 | - audit_content == 'archive' 43 | ansible.builtin.unarchive: 44 | src: "{{ audit_conf_source }}" 45 | dest: "{{ audit_conf_dest }}" 46 | 47 | - name: Pre Audit Setup | Get audit content from url 48 | when: 49 | - audit_content == 'get_url' 50 | ansible.builtin.unarchive: 51 | src: "{{ audit_conf_source }}" 52 | dest: "{{ audit_conf_dest }}/{{ benchmark }}-Audit" 53 | remote_src: "{{ ( audit_conf_source is contains ('http'))| ternary(true, false ) }}" 54 | extra_opts: "{{ (audit_conf_source is contains ('github')) | ternary('--strip-components=1', [] ) }}" 55 | 56 | - name: Pre Audit Setup | Check Goss is available 57 | when: 58 | - run_audit 59 | block: 60 | - name: Pre Audit Setup | Check for goss file 61 | ansible.builtin.stat: 62 | path: "{{ audit_bin }}" 63 | register: goss_available 64 | 65 | - name: Pre Audit Setup | If audit ensure goss is available 66 | when: 67 | - not goss_available.stat.exists 68 | ansible.builtin.assert: 69 | msg: "Audit has been selected: unable to find goss binary at {{ audit_bin }}" 70 | 71 | - name: Pre Audit Setup | Copy ansible default vars values to test audit 72 | tags: 73 | - goss_template 74 | - run_audit 75 | when: 76 | - run_audit 77 | ansible.builtin.template: 78 | src: ansible_vars_goss.yml.j2 79 | dest: "{{ audit_vars_path }}" 80 | mode: '0600' 81 | 82 | - name: Pre Audit | Run pre_remediation {{ benchmark }} audit 83 | ansible.builtin.shell: "{{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -o {{ pre_audit_outfile }} -g \"{{ group_names }}\"" 84 | changed_when: true 85 | environment: 86 | AUDIT_BIN: "{{ audit_bin }}" 87 | AUDIT_CONTENT_LOCATION: "{{ audit_conf_dest | default('/opt') }}" 88 | AUDIT_FILE: goss.yml 89 | 90 | - name: Pre Audit | Capture audit data if json format 91 | when: 92 | - audit_format == "json" 93 | block: 94 | - name: Pre Audit | Capture audit data if json format 95 | ansible.builtin.shell: grep -E '\"summary-line.*Count:.*Failed' "{{ pre_audit_outfile }}" | cut -d'"' -f4 96 | register: pre_audit_summary 97 | changed_when: false 98 | 99 | - name: Pre Audit | Set Fact for audit summary 100 | ansible.builtin.set_fact: 101 | pre_audit_results: "{{ pre_audit_summary.stdout }}" 102 | 103 | - name: Pre Audit | Capture audit data if documentation format 104 | when: 105 | - audit_format == "documentation" 106 | block: 107 | - name: Pre Audit | Capture audit data if documentation format 108 | ansible.builtin.shell: tail -2 "{{ pre_audit_outfile }}" | tac | tr '\n' ' ' 109 | register: pre_audit_summary 110 | changed_when: false 111 | 112 | - name: Pre Audit | Set Fact for audit summary 113 | ansible.builtin.set_fact: 114 | pre_audit_results: "{{ pre_audit_summary.stdout }}" 115 | 116 | - name: Audit_Only | Run Audit Only 117 | when: 118 | - audit_only 119 | ansible.builtin.import_tasks: 120 | file: audit_only.yml 121 | -------------------------------------------------------------------------------- /tasks/prelim.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: PRELIM | Set bootloader type 4 | block: 5 | - name: "PRELIM | Check whether machine is UEFI-based" 6 | ansible.builtin.stat: 7 | path: /sys/firmware/efi 8 | register: rhel8_efi_boot 9 | 10 | - name: "PRELIM | Set fact if UEFI boot" 11 | ansible.builtin.set_fact: 12 | rhel8stig_bootloader_path: /boot/efi/EFI/{{ ansible_distribution | lower }} 13 | rhel8stig_legacy_boot: false 14 | when: 15 | - rhel8_efi_boot.stat.exists 16 | 17 | - name: "PRELIM | Set fact if UEFI boot | Oracle Linux" 18 | ansible.builtin.set_fact: 19 | rhel8stig_bootloader_path: /boot/efi/EFI/redhat 20 | rhel8stig_legacy_boot: false 21 | when: 22 | - rhel8_efi_boot.stat.exists 23 | - ansible_distribution == 'OracleLinux' 24 | 25 | - name: "PRELIM | Set if not UEFI boot" 26 | ansible.builtin.set_fact: 27 | rhel8stig_bootloader_path: /boot/grub2/ 28 | rhel8stig_legacy_boot: true 29 | when: not rhel8_efi_boot.stat.exists 30 | 31 | - name: PRELIM | output bootloader and efi state 32 | ansible.builtin.debug: 33 | msg: 34 | - "bootloader path set to {{ rhel8stig_bootloader_path }}" 35 | - "legacy boot equals {{ rhel8stig_legacy_boot }}" 36 | tags: 37 | - always 38 | 39 | - name: "PRELIM | Gather interactive user ID min" 40 | block: 41 | - name: "PRELIM | Gather interactive user ID min" 42 | ansible.builtin.shell: grep ^UID_MIN /etc/login.defs | awk '{print $2}' 43 | changed_when: false 44 | failed_when: false 45 | register: rhel8stig_min_uid 46 | 47 | - name: "PRELIM | Gather interactive user ID max" 48 | ansible.builtin.shell: grep ^UID_MAX /etc/login.defs | awk '{print $2}' 49 | changed_when: false 50 | failed_when: false 51 | register: rhel8stig_max_uid 52 | 53 | - name: "PRELIM | Setting the fact" 54 | ansible.builtin.set_fact: 55 | rhel8stig_interactive_uid_start: "{{ rhel8stig_min_uid.stdout | string }}" 56 | rhel8stig_interactive_uid_stop: "{{ rhel8stig_max_uid.stdout | string }}" 57 | tags: 58 | - always 59 | 60 | - name: "PRELIM | RHEL-08-010400 | RHEL-08-020250 | RHEL-08-020290 | Set sssd.conf location" 61 | block: 62 | - name: "PRELIM | RHEL-08-010400 | RHEL-08-020250 | RHEL-08-020290 | Get sssd.conf location" 63 | ansible.builtin.stat: 64 | path: "{{ rhel8stig_sssd_conf }}" 65 | register: rhel8stig_sssd_conf_present 66 | 67 | - name: "PRELIM | RHEL-08-010400 | RHEL-08-020250 | RHEL-08-020290 | Get sssd.conf location | Warning if not found" 68 | ansible.builtin.debug: 69 | msg: "Warning!! The configured sssd config file {{ rhel8stig_sssd_conf }} has not been found, some items will skip" 70 | changed_when: true 71 | when: 72 | - not rhel8stig_sssd_conf_present.stat.exists 73 | when: 74 | - rhel_08_010400 or 75 | rhel_08_020090 or 76 | rhel_08_020250 or 77 | rhel_08_020290 78 | tags: 79 | - always 80 | 81 | - name: "PRELIM | Include audit specific variables" 82 | ansible.builtin.include_vars: 83 | file: audit.yml 84 | when: 85 | - run_audit or audit_only 86 | - setup_audit 87 | tags: 88 | - setup_audit 89 | - run_audit 90 | 91 | - name: "PRELIM | Include pre-remediation audit tasks" 92 | ansible.builtin.import_tasks: 93 | file: pre_remediation_audit.yml 94 | when: 95 | - run_audit or audit_only 96 | - setup_audit 97 | tags: 98 | - run_audit 99 | 100 | - name: "PRELIM | Find boot partition" 101 | ansible.builtin.shell: if [ -d /sys/firmware/efi ]; then echo "/boot/efi" ; else echo "/boot"; fi 102 | changed_when: false 103 | check_mode: false 104 | register: prelim_rhel8stig_boot_part 105 | tags: 106 | - always 107 | 108 | - name: "PRELIM | Find boot partition UUID" 109 | ansible.builtin.shell: if [ -d /sys/firmware/efi ]; then lsblk -l -o +UUID | grep -i efi | awk '{print $NF}'; else lsblk -l -o +UUID | grep -w '/boot' | grep -v efi | awk '{print $NF}'; fi 110 | changed_when: false 111 | check_mode: false 112 | register: prelim_rhel8stig_boot_uuid 113 | when: 114 | - rhel_08_010020 115 | tags: 116 | - always 117 | 118 | - name: "PRELIM | RHEL-08-010020 | Crypto-policies-scripts package for FIPS" 119 | ansible.builtin.package: 120 | name: crypto-policies-scripts 121 | state: present 122 | when: 123 | - "'crypto-policies-scripts' not in ansible_facts.packages" 124 | - rhel_08_010020 125 | tags: 126 | - RHEL-08-010020 127 | - CAT1 128 | - CCI-000068 129 | - SRG-OS-000033-GPOS-00014 130 | - SV-230223r792855_rule 131 | - V-230223 132 | 133 | - name: "PRELIM | RHEL-08-010020 | RHEL-08-010140 | RHEL-08-010150| Install grub2-tools." 134 | ansible.builtin.package: 135 | name: grub2-tools 136 | when: 137 | - not system_is_container 138 | - "'grub2-tools' not in ansible_facts.packages" 139 | - rhel_08_010020 or 140 | rhel_08_010140 or 141 | rhel_08_010150 142 | tags: 143 | - cat1 144 | - high 145 | - RHEL-08-010020 146 | - RHEL-08-010140 147 | - RHEL-08-010150 148 | 149 | - name: "PRELIM | Discover Gnome Desktop Environment" 150 | tags: 151 | - always 152 | ansible.builtin.stat: 153 | path: /usr/share/gnome/gnome-version.xml 154 | register: prelim_gnome_present 155 | 156 | - name: "PRELIM | dconf" 157 | block: 158 | - name: "PRELIM | Install dconf" 159 | ansible.builtin.package: 160 | name: dconf 161 | when: 162 | - "'dconf' not in ansible_facts.packages" 163 | - rhel8stig_gui 164 | 165 | - name: "PRELIM | dconf directory structure setup" 166 | ansible.builtin.file: 167 | path: /etc/dconf/db/local.d/locks 168 | state: directory 169 | mode: 'u+x,go-w' 170 | when: 171 | - rhel8stig_always_configure_dconf 172 | when: 173 | - rhel_08_010050 or 174 | rhel_08_020030 or 175 | rhel_08_020050 or 176 | rhel_08_020060 or 177 | rhel_08_020080 or 178 | rhel_08_020090 179 | # rhel_08_040180 - removed from section 1 waiting to see if it comes up somewhere else 180 | tags: 181 | - rhel_08_010050 182 | - rhel_08_020030 183 | - rhel_08_020050 184 | - rhel_08_020060 185 | - rhel_08_020080 186 | - rhel_08_020090 187 | # - rhel_08_040180 - removed from section 1 waiting to see if it comes up somewhere else 188 | 189 | - name: "PRELIM | Find all sudoers files." 190 | ansible.builtin.shell: "find /etc/sudoers /etc/sudoers.d/ -type f ! -name '*~' ! -name '*.*'" 191 | check_mode: false 192 | changed_when: false 193 | failed_when: false 194 | register: rhel8stig_sudoers_files 195 | when: 196 | - rhel_08_010380 or 197 | rhel_08_010381 198 | tags: 199 | - cat2 200 | - medium 201 | - RHEL-08-010380 202 | - sudo 203 | 204 | - name: "PRELIM | Gather chroot status" 205 | ansible.builtin.setup: 206 | gather_subset: chroot,!all,!min 207 | filter: ansible_is_chroot 208 | when: 209 | - ansible_is_chroot is not defined 210 | tags: 211 | - always 212 | 213 | - name: "PRELIM | Gather mount information" 214 | ansible.builtin.setup: 215 | gather_subset: hardware,!all,!min 216 | filter: ansible_mounts 217 | when: 218 | - ansible_mounts is not defined 219 | tags: 220 | - always 221 | 222 | - name: "PRELIM | Ensure cronie is available" 223 | ansible.builtin.package: 224 | name: cronie 225 | when: 226 | - not system_is_container 227 | - "'cronie' not in ansible_facts.packages" 228 | - rhel_08_010360 229 | tags: 230 | - cat2 231 | - medium 232 | - RHEL-08-010360 233 | 234 | - name: "PRELIM | RHEL-08-010740 | RHEL-08-010750 | RHEL-08-020320 | Parse /etc/passwd" 235 | ansible.builtin.import_tasks: parse_etc_passwd.yml 236 | vars: 237 | rhel8stig_passwd_tasks: "RHEL-08-010740 RHEL-08-010750 RHEL-08-020320" # pragma: allowlist secret 238 | when: 239 | - rhel_08_010141 or 240 | rhel_08_010149 or 241 | rhel_08_010731 or 242 | rhel_08_010740 or 243 | rhel_08_010750 or 244 | rhel_08_020320 245 | tags: 246 | - cat2 247 | - medium 248 | - RHEL-08-010141 249 | - RHEL-08-010149 250 | - RHEL-08-010731 251 | - RHEL-08-010740 252 | - RHEL-08-010750 253 | - RHEL-08-020320 254 | 255 | - name: "PRELIM | AUDIT | Discover Interactive Users" 256 | tags: 257 | - always 258 | ansible.builtin.shell: > 259 | grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false") { print $1 }' 260 | changed_when: false 261 | register: discovered_interactive_usernames 262 | 263 | - name: "PRELIM | AUDIT | Discover Interactive User accounts home directories" 264 | tags: 265 | - always 266 | ansible.builtin.shell: > 267 | grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false") { print $6 }' 268 | changed_when: false 269 | register: discovered_interactive_users_home 270 | 271 | - name: "PRELIM | AUDIT | Discover Interactive user UIDs" 272 | tags: 273 | - always 274 | ansible.builtin.shell: > 275 | grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false") { print $3 }' 276 | changed_when: false 277 | register: discovered_interactive_uids 278 | 279 | - name: "PRELIM | RHEL-08-010690 | Ensure user enumeration command is modified when autofs remote home directories are in use" 280 | block: 281 | - name: PRELIM | RHEL-08-010690 | AUDIT | Ensure that rhel8stig_auto_mount_home_dirs_local_mount_point is defined and not length zero 282 | ansible.builtin.assert: 283 | that: 284 | - rhel8stig_auto_mount_home_dirs_local_mount_point is defined 285 | - rhel8stig_auto_mount_home_dirs_local_mount_point | length > 0 286 | 287 | - name: PRELIM | RHEL-08-010690 | PATCH | Modify local_interactive_user_dir_command to exclude remote automounted home directories 288 | ansible.builtin.set_fact: 289 | local_interactive_user_dir_command: "{{ local_interactive_user_dir_command }} | grep -v '{{ rhel8stig_auto_mount_home_dirs_local_mount_point }}" 290 | 291 | when: 292 | - rhel8stig_autofs_remote_home_dirs 293 | tags: 294 | - RHEL-08-010690 295 | - complexity-high 296 | 297 | - name: "PRELIM | RHEL-08-010690 | Gather local interactive user directories" 298 | ansible.builtin.shell: "{{ local_interactive_user_dir_command }}" 299 | register: rhel_08_010690_getent 300 | changed_when: false 301 | failed_when: false 302 | tags: 303 | - RHEL-08-010690 304 | - complexity-high 305 | 306 | - name: "PRELIM | RHEL-08-010690 | Set fact for home directory paths for interactive users" 307 | ansible.builtin.set_fact: 308 | rhel_08_stig_interactive_homedir_results: "{{ rhel_08_010690_getent.stdout_lines }}" 309 | when: rhel_08_010690_getent.stdout_lines is defined 310 | tags: 311 | - RHEL-08-010690 312 | - complexity-high 313 | 314 | - name: "PRELIM | RHEL-08-010070 | RHEL-08-030010 | Ensure rsyslog is installed when required." 315 | ansible.builtin.package: 316 | name: rsyslog 317 | when: 318 | - not system_is_container 319 | - rhel_08_010070 or 320 | rhel_08_030010 321 | - "'rsyslog' not in ansible_facts.packages" 322 | tags: 323 | - cat2 324 | - medium 325 | - RHEL-08-010070 326 | - RHEL-08-030010 327 | 328 | - name: "PRELIM | RHEL-08-030620 | RHEL-08-030630 | RHEL-08-030640 | RHEL-08-030650 | Install audit remote plugin." 329 | ansible.builtin.package: 330 | name: audispd-plugins 331 | when: 332 | - not system_is_container 333 | - rhel_08_030620 or 334 | rhel_08_030630 or 335 | rhel_08_030640 or 336 | rhel_08_030650 337 | - "'audispd-plugins' not in ansible_facts.packages" 338 | tags: 339 | - cat2 340 | - medium 341 | - auditd 342 | - RHEL-08-030620 343 | - RHEL-08-030630 344 | - RHEL-08-030640 345 | - RHEL-08-030650 346 | 347 | - name: "PRELIM | RHEL-08-010360 | RHEL-08-010380 | RHEL-08-040310 | Install and initialize AIDE" 348 | block: 349 | - name: "PRELIM | RHEL-08-010360 | RHEL-08-010380 | RHEL-08-040310 | Install AIDE" 350 | ansible.builtin.package: 351 | name: aide 352 | state: present 353 | notify: "{{ rhel8stig_aide_handler }}" 354 | when: 355 | - "'aide' not in ansible_facts.packages" 356 | 357 | - name: "PRELIM | RHEL-08-010360 | RHEL-08-010380 | RHEL-08-040310 | Check for existing AIDE database" 358 | ansible.builtin.stat: 359 | path: "{{ rhel8stig_aide_db_file }}" 360 | register: rhel8stig_aide_db_status 361 | check_mode: false 362 | changed_when: false 363 | notify: "{{ rhel8stig_aide_handler }}" 364 | when: 365 | - not system_is_container 366 | - rhel_08_010360 or 367 | rhel_08_010380 or 368 | rhel_08_040310 369 | tags: 370 | - cat2 371 | - medium 372 | - patch 373 | - aide 374 | - RHEL-08-010360 375 | - RHEL-08-010380 376 | - RHEL-08-040310 377 | 378 | - name: "PRELIM | RHEL-08-010170 | RHEL-08-010450 | Install SELinux related dependencies" 379 | ansible.builtin.package: 380 | name: libselinux-utils 381 | state: present 382 | when: 383 | - not system_is_container 384 | - "'libselinux-utils' not in ansible_facts.packages" 385 | - rhel_08_010170 or 386 | rhel_08_010450 387 | 388 | - name: "PRELIM | Bare bones SSH Server" 389 | block: 390 | - name: "PRELIM | Install SSH" 391 | ansible.builtin.package: 392 | name: openssh-server 393 | state: present 394 | when: 395 | - "'openssh-server' not in ansible_facts.packages" 396 | 397 | - name: PRELIM | Start SSH 398 | ansible.builtin.service: 399 | name: sshd 400 | state: "{{ rhel8stig_service_started }}" 401 | enabled: true 402 | 403 | - name: PRELIM | Check if ssh host key exists 404 | ansible.builtin.stat: 405 | path: /etc/ssh/ssh_host_rsa_key 406 | register: rhel8stig_ssh_host_rsa_key_stat 407 | 408 | - name: PRELIM | Create ssh host key to allow 'sshd -t -f %s' to succeed 409 | ansible.builtin.shell: ssh-keygen -N '' -f /etc/ssh/ssh_host_rsa_key -t rsa -b 4096 410 | when: not rhel8stig_ssh_host_rsa_key_stat.stat.exists 411 | notify: clean up ssh host key 412 | when: 413 | - rhel8stig_ssh_required 414 | 415 | - name: "PRELIM | RHEL-08-010660 | RHEL-08-010770 | AUDIT | Find ini files for interactive users." 416 | ansible.builtin.shell: find "{{ item }}" -maxdepth 1 -type f | grep '/\.[^/]*' 417 | with_items: "{{ rhel_08_stig_interactive_homedir_results }}" 418 | register: rhel_08_010770_ini_file_list 419 | changed_when: false 420 | failed_when: false 421 | when: 422 | - rhel_08_stig_interactive_homedir_results is defined 423 | - rhel8stig_disruption_high 424 | - rhel_08_010660 or 425 | rhel_08_010770 426 | tags: 427 | - RHEL-08-010660 428 | - RHEL-08-010770 429 | - complexity-high 430 | 431 | - name: "PRELIM | RHEL-08-010660 | RHEL-08-010770 | Set fact for home directory paths for interactive users" 432 | ansible.builtin.set_fact: 433 | rhel_08_stig_interactive_homedir_inifiles: "{{ rhel_08_010770_ini_file_list.results | map(attribute='stdout_lines') | list }}" 434 | when: 435 | - rhel_08_stig_interactive_homedir_results is defined 436 | - rhel8stig_disruption_high 437 | - rhel_08_010660 or 438 | rhel_08_010770 439 | tags: 440 | - RHEL-08-010660 441 | - RHEL-08-010770 442 | - complexity-high 443 | 444 | - name: "PRELIM | Gather the package facts" 445 | ansible.builtin.package_facts: 446 | manager: auto 447 | tags: 448 | - always 449 | 450 | - name: "PRELIM | RHEL-08-020017 | RHEL-08-020027 | RHEL-08-020028 | If using selinux set up system prereqs" 451 | block: 452 | - name: "PRELIM | RHEL-08-020017 | Install policycoreutils-python-utils" 453 | ansible.builtin.package: 454 | name: policycoreutils-python-utils 455 | state: present 456 | when: "'policycoreutils-python-utils' not in ansible_facts.packages" 457 | 458 | - name: "PRELIM | RHEL-08-020027 | create faillock dir if rhel_08_020027" 459 | ansible.builtin.file: 460 | path: "{{ rhel8stig_pam_faillock.dir }}" 461 | state: directory 462 | mode: 'u+x,go-w' 463 | owner: root 464 | group: root 465 | recurse: true 466 | setype: faillog_t 467 | register: faillock_dir 468 | when: 469 | - not system_is_container 470 | - rhel_08_020017 or 471 | rhel_08_020027 or 472 | rhel_08_020028 473 | 474 | - name: "PRELIM | Section 1.1 | Create list of mount points" 475 | ansible.builtin.set_fact: 476 | mount_names: "{{ ansible_mounts | map(attribute='mount') | list }}" 477 | -------------------------------------------------------------------------------- /templates/01-banner-message.j2: -------------------------------------------------------------------------------- 1 | [org/gnome/login-screen] 2 | banner-message-enable=true 3 | 4 | banner-message-text='{{ rhel8stig_logon_banner }}' 5 | -------------------------------------------------------------------------------- /templates/01_users.j2: -------------------------------------------------------------------------------- 1 | ## Configured for DISA STIG control 010141 and 010149 2 | ## Using Ansible playbook 3 | #!/bin/sh -e 4 | cat << EOF 5 | if [ -f \${prefix}/user.cfg ]; then 6 | source \${prefix}/user.cfg 7 | if [ -n "\${GRUB2_PASSWORD}" ]; then 8 | set superusers="{{ rhel8stig_boot_superuser }}" 9 | export superusers 10 | password_pbkdf2 {{ rhel8stig_boot_superuser }} \${GRUB2_PASSWORD} 11 | fi 12 | fi 13 | EOF 14 | -------------------------------------------------------------------------------- /templates/aide.conf.j2: -------------------------------------------------------------------------------- 1 | # Example configuration file for AIDE. 2 | 3 | @@define DBDIR /var/lib/aide 4 | @@define LOGDIR /var/log/aide 5 | 6 | # The location of the database to be read. 7 | database=file:@@{DBDIR}/aide.db.gz 8 | 9 | # The location of the database to be written. 10 | #database_out=sql:host:port:database:login_name:passwd:table 11 | #database_out=file:aide.db.new 12 | database_out=file:@@{DBDIR}/aide.db.new.gz 13 | 14 | # Whether to gzip the output to database. 15 | gzip_dbout=yes 16 | 17 | # Default. 18 | verbose=5 19 | 20 | report_url=file:@@{LOGDIR}/aide.log 21 | report_url=stdout 22 | #report_url=stderr 23 | #NOT IMPLEMENTED report_url=mailto:root@foo.com 24 | #NOT IMPLEMENTED report_url=syslog:LOG_AUTH 25 | 26 | # These are the default rules. 27 | # 28 | #p: permissions 29 | #i: inode: 30 | #n: number of links 31 | #u: user 32 | #g: group 33 | #s: size 34 | #b: block count 35 | #m: mtime 36 | #a: atime 37 | #c: ctime 38 | #S: check for growing size 39 | #acl: Access Control Lists 40 | #selinux SELinux security context 41 | #xattrs: Extended file attributes 42 | #md5: md5 checksum 43 | #sha1: sha1 checksum 44 | #sha256: sha256 checksum 45 | #sha512: sha512 checksum 46 | #rmd160: rmd160 checksum 47 | #tiger: tiger checksum 48 | 49 | #haval: haval checksum (MHASH only) 50 | #gost: gost checksum (MHASH only) 51 | #crc32: crc32 checksum (MHASH only) 52 | #whirlpool: whirlpool checksum (MHASH only) 53 | 54 | FIPSR = p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha256 55 | 56 | #R: p+i+n+u+g+s+m+c+acl+selinux+xattrs+md5 57 | #L: p+i+n+u+g+acl+selinux+xattrs 58 | #E: Empty group 59 | #>: Growing logfile p+u+g+i+n+S+acl+selinux+xattrs 60 | 61 | # You can create custom rules like this. 62 | # With MHASH... 63 | # ALLXTRAHASHES = sha1+rmd160+sha512+whirlpool+tiger+haval+gost+crc32 64 | # ALLXTRAHASHES = sha512 65 | 66 | # Everything but access time (Ie. all changes) 67 | EVERYTHING = FIPSR 68 | 69 | # Sane, with one good hash. 70 | # NORMAL = sha512 71 | NORMAL = FIPSR 72 | 73 | # For directories, don't bother doing hashes. 74 | DIR = FIPSR 75 | 76 | # Access control only. 77 | PERMS = FIPSR 78 | 79 | # Access + inode changes + file type. 80 | STATIC = FIPSR+ftype 81 | 82 | # Logfiles only check access w/o xattrs. 83 | LOG = FIPSR+ftype 84 | 85 | # Content + file type. 86 | CONTENT = FIPSR+ftype 87 | 88 | # Extended content + file type + access. 89 | CONTENT_EX = FIPSR 90 | 91 | # Some files get updated automatically, so the inode/ctime/mtime change 92 | # but we want to know when the data inside them changes. 93 | DATAONLY = FIPSR 94 | 95 | # Next decide what directories/files you want in the database. Aide 96 | # uses a first match system. Put file specific instructions before generic 97 | # matches. e.g. Put file matches before directories. 98 | 99 | /boot/ CONTENT_EX 100 | /bin/ CONTENT_EX 101 | /sbin/ CONTENT_EX 102 | /lib/ CONTENT_EX 103 | /lib64/ CONTENT_EX 104 | /opt/ CONTENT 105 | 106 | # Admin's dot files constantly change, just check perms. 107 | /root/\..* PERMS 108 | # Otherwise get all of /root. 109 | /root/ CONTENT_EX 110 | 111 | # These are too volatile. 112 | !/usr/src/ 113 | !/usr/tmp/ 114 | # Otherwise get all of /usr. 115 | /usr/ CONTENT_EX 116 | 117 | # Check only permissions, user, group, seliunx for /etc, but 118 | # cover some important files closely. 119 | !/etc/mtab$ 120 | 121 | # Ignore backup files 122 | !/etc/.*~ 123 | 124 | # trusted databases 125 | /etc/hosts$ CONTENT_EX 126 | /etc/host.conf$ CONTENT_EX 127 | /etc/hostname$ CONTENT_EX 128 | /etc/issue$ CONTENT_EX 129 | /etc/issue.net$ CONTENT_EX 130 | /etc/protocols$ CONTENT_EX 131 | /etc/services$ CONTENT_EX 132 | /etc/localtime$ CONTENT_EX 133 | /etc/alternatives/ CONTENT_EX 134 | /etc/mime.types$ CONTENT_EX 135 | /etc/terminfo/ CONTENT_EX 136 | /etc/exports$ CONTENT_EX 137 | /etc/fstab$ CONTENT_EX 138 | /etc/passwd$ CONTENT_EX 139 | /etc/group$ CONTENT_EX 140 | /etc/gshadow$ CONTENT_EX 141 | /etc/shadow$ CONTENT_EX 142 | /etc/security/opasswd$ CONTENT_EX 143 | /etc/skel/ CONTENT_EX 144 | 145 | # networking 146 | /etc/hosts.allow$ CONTENT_EX 147 | /etc/hosts.deny$ CONTENT_EX 148 | /etc/firewalld/ CONTENT_EX 149 | /etc/NetworkManager/ CONTENT_EX 150 | /etc/networks$ CONTENT_EX 151 | /etc/dhcp/ CONTENT_EX 152 | /etc/wpa_supplicant/ CONTENT_EX 153 | /etc/resolv.conf$ DATAONLY 154 | /etc/nscd.conf$ NORMAL 155 | 156 | # logins and accounts 157 | /etc/login.defs$ CONTENT_EX 158 | /etc/libuser.conf$ CONTENT_EX 159 | /var/log/faillog$ PERMS 160 | /var/log/lastlog$ PERMS 161 | /var/run/faillock/ PERMS 162 | /etc/pam.d/ CONTENT_EX 163 | /etc/security$ CONTENT_EX 164 | /etc/securetty$ CONTENT_EX 165 | /etc/polkit-1/ CONTENT_EX 166 | /etc/sudo.conf$ CONTENT_EX 167 | /etc/sudoers$ CONTENT_EX 168 | /etc/sudoers.d/ CONTENT_EX 169 | 170 | # Shell/X starting files 171 | /etc/profile$ CONTENT_EX 172 | /etc/profile.d/ CONTENT_EX 173 | /etc/bashrc$ CONTENT_EX 174 | /etc/bash_completion.d/ CONTENT_EX 175 | /etc/zprofile$ CONTENT_EX 176 | /etc/zshrc$ CONTENT_EX 177 | /etc/zlogin$ CONTENT_EX 178 | /etc/zlogout$ CONTENT_EX 179 | /etc/X11/ CONTENT_EX 180 | /etc/shells$ CONTENT_EX 181 | 182 | # Pkg manager 183 | /etc/yum.conf$ CONTENT_EX 184 | /etc/yumex.conf$ CONTENT_EX 185 | /etc/yumex.profiles.conf$ CONTENT_EX 186 | /etc/yum/ CONTENT_EX 187 | /etc/yum.repos.d/ CONTENT_EX 188 | 189 | # This gets new/removes-old filenames daily. 190 | !/var/log/sa/ 191 | # As we are checking it, we've truncated yesterdays size to zero. 192 | !/var/log/aide.log 193 | 194 | # auditing 195 | # AIDE produces an audit record, so this becomes perpetual motion. 196 | # /var/log/audit/ PERMS+ANF+ARF 197 | /etc/audit/ CONTENT_EX 198 | /etc/audisp/ CONTENT_EX 199 | /etc/libaudit.conf$ CONTENT_EX 200 | /etc/aide.conf$ CONTENT_EX 201 | 202 | # System logs 203 | /etc/rsyslog.conf$ CONTENT_EX 204 | /etc/rsyslog.d/ CONTENT_EX 205 | /etc/logrotate.conf$ CONTENT_EX 206 | /etc/logrotate.d/ CONTENT_EX 207 | /var/log/ LOG+ANF+ARF 208 | /var/run/utmp$ LOG 209 | 210 | # secrets 211 | /etc/pkcs11/ CONTENT_EX 212 | /etc/pki/ CONTENT_EX 213 | /etc/ssl/ CONTENT_EX 214 | /etc/certmonger/ CONTENT_EX 215 | 216 | # init system 217 | /etc/systemd/ CONTENT_EX 218 | /etc/sysconfig/ CONTENT_EX 219 | /etc/rc.d/ CONTENT_EX 220 | /etc/tmpfiles.d/ CONTENT_EX 221 | /etc/machine-id$ CONTENT_EX 222 | 223 | # boot config 224 | /etc/grub.d/ CONTENT_EX 225 | /etc/grub2.cfg$ CONTENT_EX 226 | /etc/dracut.conf$ CONTENT_EX 227 | /etc/dracut.conf.d/ CONTENT_EX 228 | 229 | # glibc linker 230 | /etc/ld.so.cache$ CONTENT_EX 231 | /etc/ld.so.conf$ CONTENT_EX 232 | /etc/ld.so.conf.d/ CONTENT_EX 233 | 234 | # kernel config 235 | /etc/sysctl.conf$ CONTENT_EX 236 | /etc/sysctl.d/ CONTENT_EX 237 | /etc/modprobe.d/ CONTENT_EX 238 | /etc/modules-load.d/ CONTENT_EX 239 | /etc/depmod.d/ CONTENT_EX 240 | /etc/udev/ CONTENT_EX 241 | /etc/crypttab$ CONTENT_EX 242 | 243 | #### Daemons #### 244 | 245 | # cron jobs 246 | /var/spool/at/ CONTENT 247 | /etc/at.allow$ CONTENT 248 | /etc/at.deny$ CONTENT 249 | /etc/cron.allow$ CONTENT_EX 250 | /etc/cron.deny$ CONTENT_EX 251 | /etc/cron.d/ CONTENT_EX 252 | /etc/cron.daily/ CONTENT_EX 253 | /etc/cron.hourly/ CONTENT_EX 254 | /etc/cron.monthly/ CONTENT_EX 255 | /etc/cron.weekly/ CONTENT_EX 256 | /etc/crontab$ CONTENT_EX 257 | /var/spool/cron/root/ CONTENT 258 | /etc/anacrontab$ CONTENT_EX 259 | 260 | # time keeping 261 | /etc/ntp.conf$ CONTENT_EX 262 | /etc/ntp/ CONTENT_EX 263 | /etc/chrony.conf$ CONTENT_EX 264 | /etc/chrony.keys$ CONTENT_EX 265 | 266 | # mail 267 | /etc/aliases$ CONTENT_EX 268 | /etc/aliases.db$ CONTENT_EX 269 | /etc/postfix/ CONTENT_EX 270 | /etc/mail.rc$ CONTENT_EX 271 | /etc/mailcap$ CONTENT_EX 272 | 273 | # ssh 274 | /etc/ssh/sshd_config$ CONTENT_EX 275 | /etc/ssh/ssh_config$ CONTENT_EX 276 | 277 | # stunnel 278 | /etc/stunnel/ CONTENT_EX 279 | 280 | # ftp 281 | /etc/vsftpd.conf$ CONTENT 282 | /etc/vsftpd/ CONTENT 283 | 284 | # printing 285 | /etc/cups/ CONTENT_EX 286 | /etc/cupshelpers/ CONTENT_EX 287 | /etc/avahi/ CONTENT_EX 288 | 289 | # web server 290 | /etc/httpd/ CONTENT_EX 291 | 292 | # dns 293 | /etc/named/ CONTENT_EX 294 | /etc/named.conf$ CONTENT_EX 295 | /etc/named.iscdlv.key$ CONTENT_EX 296 | /etc/named.rfc1912.zones$ CONTENT_EX 297 | /etc/named.root.key$ CONTENT_EX 298 | 299 | # xinetd 300 | /etc/xinetd.d/ CONTENT_EX 301 | 302 | # Now everything else in /etc. 303 | /etc/ PERMS 304 | 305 | # With AIDE's default verbosity level of 5, these would give lots of 306 | # warnings upon tree traversal. It might change with future version. 307 | # 308 | #=/lost\+found DIR 309 | #=/home DIR 310 | 311 | # Audit Tools 312 | /usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512 313 | /usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512 314 | /usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512 315 | /usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512 316 | /usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512 317 | /usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512 318 | /usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512 319 | 320 | 321 | # Ditto /var/log/sa/ same reason... 322 | !/var/log/httpd/ 323 | -------------------------------------------------------------------------------- /templates/ansible_vars_goss.yml.j2: -------------------------------------------------------------------------------- 1 | 2 | ## metadata for Audit benchmark 3 | benchmark_version: {{ benchmark_version }} 4 | 5 | rhel8stig_os_distribution: {{ ansible_facts['distribution'] | lower }} 6 | 7 | gpg_keys: 8 | {% for info in gpg_keys %} 9 | - name: {{ info.name }} 10 | fingerprint: {{ info.fingerprint }} 11 | {% endfor %} 12 | rpm_gpg_key: {{ rpm_gpg_key }} 13 | 14 | rhel8stig_os_version_pre_8_2: {% if ansible_facts['distribution_version'] is version('8.1', '<=') %}true{% else %}false{% endif %} 15 | 16 | OS_ver: {{ ansible_facts['distribution_version'] }} 17 | 18 | # Some tests may need to scan every filesystem or have an impact on a system 19 | # these may need be scheduled to minimise impact also ability to set a timeout if taking too long 20 | run_heavy_tests: {{ audit_run_heavy_tests }} 21 | timeout_ms: {{ audit_cmd_timeout }} 22 | 23 | ### Remediation Settings 24 | 25 | # turn the categories on/off 26 | rhel8stig_cat1: {{ rhel8stig_cat1 }} 27 | rhel8stig_cat2: {{ rhel8stig_cat2 }} 28 | rhel8stig_cat3: {{ rhel8stig_cat3 }} 29 | 30 | 31 | # If using the supplied graphical interface 32 | rhel8stig_gui: {{ rhel8stig_gui }} 33 | 34 | # system acts or requires router networking options 35 | rhel8stig_system_is_router: {{ rhel8stig_system_is_router }} 36 | 37 | # Discovered items to assist with skips some audit checks 38 | skip_sssd_check: {% if rhel8stig_sssd_conf_present.stat.exists %}False{% else %}True{% endif %} 39 | 40 | skip_postfix_check: {% if 'postfix' not in ansible_facts.packages %}True{% else %}False{% endif %} 41 | 42 | skip_tftp_check: {% if rhel8stig_tftp_required %}False{% else %}True{% endif %} 43 | 44 | 45 | # Sets up the system dependant on bootloader 46 | legacy_boot: {{ rhel8stig_legacy_boot }} 47 | rhel8stig_bootloader_path: {{ rhel8stig_bootloader_path }} 48 | 49 | 50 | # Cat 1 rules 51 | RHEL_08_010000: {{ rhel_08_010000 }} 52 | RHEL_08_010020: {{ rhel_08_010020 }} 53 | RHEL_08_010121: {{ rhel_08_010121 }} 54 | RHEL_08_010140: {{ rhel_08_010140 }} 55 | RHEL_08_010150: {{ rhel_08_010150 }} 56 | RHEL_08_010370: {{ rhel_08_010370 }} 57 | RHEL_08_010371: {{ rhel_08_010371 }} 58 | RHEL_08_010460: {{ rhel_08_010460 }} 59 | RHEL_08_010470: {{ rhel_08_010470 }} 60 | RHEL_08_010820: {{ rhel_08_010820 }} 61 | RHEL_08_020330: {{ rhel_08_020330 }} 62 | RHEL_08_020331: {{ rhel_08_020331 }} 63 | RHEL_08_020332: {{ rhel_08_020332 }} 64 | RHEL_08_040000: {{ rhel_08_040000 }} 65 | RHEL_08_040010: {{ rhel_08_040010 }} 66 | RHEL_08_040060: {{ rhel_08_040060 }} 67 | RHEL_08_040170: {{ rhel_08_040170 }} 68 | RHEL_08_040171: {{ rhel_08_040171 }} 69 | RHEL_08_040172: {{ rhel_08_040172 }} 70 | RHEL_08_040190: {{ rhel_08_040190 }} 71 | RHEL_08_040200: {{ rhel_08_040200 }} 72 | RHEL_08_040360: {{ rhel_08_040360 }} 73 | 74 | 75 | # Cat 2 rules 76 | RHEL_08_010010: {{ rhel_08_010010 }} 77 | RHEL_08_010019: {{ rhel_08_010019 }} 78 | RHEL_08_010030: {{ rhel_08_010030 }} 79 | RHEL_08_010040: {{ rhel_08_010040 }} # Variable options below 80 | RHEL_08_010049: {{ rhel_08_010049 }} # Variable options below 81 | RHEL_08_010050: {{ rhel_08_010050 }} # Variable options below 82 | RHEL_08_010060: {{ rhel_08_010060 }} # Variable options below 83 | RHEL_08_010070: {{ rhel_08_010070 }} 84 | RHEL_08_010090: {{ rhel_08_010090 }} 85 | RHEL_08_010100: {{ rhel_08_010100 }} 86 | RHEL_08_010110: {{ rhel_08_010110 }} 87 | RHEL_08_010120: {{ rhel_08_010120 }} 88 | RHEL_08_010130: {{ rhel_08_010130 }} 89 | RHEL_08_010141: {{ rhel_08_010141 }} 90 | RHEL_08_010149: {{ rhel_08_010149 }} 91 | RHEL_08_010151: {{ rhel_08_010151 }} 92 | RHEL_08_010152: {{ rhel_08_010152 }} 93 | RHEL_08_010159: {{ rhel_08_010159 }} 94 | RHEL_08_010160: {{ rhel_08_010160 }} 95 | RHEL_08_010161: {{ rhel_08_010161 }} 96 | RHEL_08_010162: {{ rhel_08_010162 }} 97 | RHEL_08_010163: {{ rhel_08_010162 }} ### to be fixed as not yet written for V1r2 98 | RHEL_08_010170: {{ rhel_08_010170 }} 99 | RHEL_08_010180: {{ rhel_08_010180 }} 100 | RHEL_08_010190: {{ rhel_08_010190 }} 101 | RHEL_08_010200: {{ rhel_08_010200 }} 102 | RHEL_08_010201: {{ rhel_08_010201 }} 103 | RHEL_08_010210: {{ rhel_08_010210 }} 104 | RHEL_08_010220: {{ rhel_08_010220 }} 105 | RHEL_08_010230: {{ rhel_08_010230 }} 106 | RHEL_08_010240: {{ rhel_08_010240 }} 107 | RHEL_08_010250: {{ rhel_08_010250 }} 108 | RHEL_08_010260: {{ rhel_08_010260 }} 109 | RHEL_08_010287: {{ rhel_08_010287 }} 110 | RHEL_08_010290: {{ rhel_08_010290 }} 111 | RHEL_08_010291: {{ rhel_08_010291 }} 112 | RHEL_08_010293: {{ rhel_08_010293 }} 113 | RHEL_08_010294: {{ rhel_08_010294 }} 114 | RHEL_08_010295: {{ rhel_08_010295 }} 115 | RHEL_08_010300: {{ rhel_08_010300 }} 116 | RHEL_08_010310: {{ rhel_08_010310 }} 117 | RHEL_08_010320: {{ rhel_08_010320 }} 118 | RHEL_08_010330: {{ rhel_08_010330 }} 119 | RHEL_08_010331: {{ rhel_08_010331 }} 120 | RHEL_08_010340: {{ rhel_08_010340 }} 121 | RHEL_08_010341: {{ rhel_08_010341 }} 122 | RHEL_08_010350: {{ rhel_08_010350 }} 123 | RHEL_08_010351: {{ rhel_08_010351 }} 124 | RHEL_08_010358: {{ rhel_08_010358 }} 125 | RHEL_08_010359: {{ rhel_08_010359 }} 126 | RHEL_08_010360: {{ rhel_08_010360 }} 127 | RHEL_08_010372: {{ rhel_08_010372 }} 128 | RHEL_08_010373: {{ rhel_08_010373 }} 129 | RHEL_08_010374: {{ rhel_08_010374 }} 130 | RHEL_08_010379: {{ rhel_08_010379 }} 131 | RHEL_08_010380: {{ rhel_08_010380 }} 132 | RHEL_08_010381: {{ rhel_08_010380 }} 133 | RHEL_08_010382: {{ rhel_08_010382 }} 134 | RHEL_08_010383: {{ rhel_08_010383 }} 135 | RHEL_08_010384: {{ rhel_08_010384 }} 136 | RHEL_08_010385: {{ rhel_08_010385 }} 137 | RHEL_08_010390: {{ rhel_08_010390 }} 138 | RHEL_08_010400: {{ rhel_08_010400 }} 139 | RHEL_08_010410: {{ rhel_08_010410 }} 140 | RHEL_08_010420: {{ rhel_08_010420 }} 141 | RHEL_08_010421: {{ rhel_08_010421 }} 142 | RHEL_08_010422: {{ rhel_08_010422 }} 143 | RHEL_08_010423: {{ rhel_08_010423 }} 144 | RHEL_08_010430: {{ rhel_08_010430 }} 145 | RHEL_08_010450: {{ rhel_08_010450 }} 146 | RHEL_08_010472: {{ rhel_08_010472 }} 147 | RHEL_08_010480: {{ rhel_08_010480 }} 148 | RHEL_08_010490: {{ rhel_08_010490 }} 149 | RHEL_08_010500: {{ rhel_08_010500 }} 150 | RHEL_08_010520: {{ rhel_08_010520 }} 151 | RHEL_08_010521: {{ rhel_08_010521 }} 152 | RHEL_08_010522: {{ rhel_08_010522 }} 153 | RHEL_08_010543: {{ rhel_08_010543 }} 154 | RHEL_08_010544: {{ rhel_08_010544 }} 155 | RHEL_08_010550: {{ rhel_08_010550 }} 156 | RHEL_08_010561: {{ rhel_08_010561 }} 157 | RHEL_08_010570: {{ rhel_08_010570 }} 158 | RHEL_08_010571: {{ rhel_08_010571 }} 159 | RHEL_08_010572: {{ rhel_08_010572 }} 160 | RHEL_08_010580: {{ rhel_08_010580 }} 161 | RHEL_08_010590: {{ rhel_08_010590 }} 162 | RHEL_08_010600: {{ rhel_08_010600 }} 163 | RHEL_08_010610: {{ rhel_08_010610 }} 164 | RHEL_08_010620: {{ rhel_08_010620 }} 165 | RHEL_08_010630: {{ rhel_08_010630 }} 166 | RHEL_08_010640: {{ rhel_08_010640 }} 167 | RHEL_08_010650: {{ rhel_08_010650 }} 168 | RHEL_08_010660: {{ rhel_08_010660 }} 169 | RHEL_08_010670: {{ rhel_08_010670 }} 170 | RHEL_08_010671: {{ rhel_08_010671 }} 171 | RHEL_08_010672: {{ rhel_08_010672 }} 172 | RHEL_08_010673: {{ rhel_08_010673 }} 173 | RHEL_08_010674: {{ rhel_08_010674 }} 174 | RHEL_08_010675: {{ rhel_08_010675 }} 175 | RHEL_08_010680: {{ rhel_08_010680 }} 176 | RHEL_08_010690: {{ rhel_08_010690 }} 177 | RHEL_08_010700: {{ rhel_08_010700 }} 178 | RHEL_08_010710: {{ rhel_08_010710 }} 179 | RHEL_08_010720: {{ rhel_08_010720 }} 180 | RHEL_08_010730: {{ rhel_08_010730 }} 181 | RHEL_08_010731: {{ rhel_08_010731 }} 182 | RHEL_08_010740: {{ rhel_08_010740 }} 183 | RHEL_08_010741: {{ rhel_08_010741 }} 184 | RHEL_08_010750: {{ rhel_08_010750 }} 185 | RHEL_08_010760: {{ rhel_08_010760 }} 186 | RHEL_08_010770: {{ rhel_08_010770 }} 187 | RHEL_08_010780: {{ rhel_08_010780 }} 188 | RHEL_08_010790: {{ rhel_08_010790 }} 189 | RHEL_08_010800: {{ rhel_08_010800 }} 190 | RHEL_08_010830: {{ rhel_08_010830 }} 191 | RHEL_08_020000: {{ rhel_08_020000 }} 192 | RHEL_08_020010: {{ rhel_08_020010 }} 193 | RHEL_08_020011: {{ rhel_08_020011 }} 194 | RHEL_08_020012: {{ rhel_08_020012 }} 195 | RHEL_08_020013: {{ rhel_08_020013 }} 196 | RHEL_08_020014: {{ rhel_08_020014 }} 197 | RHEL_08_020015: {{ rhel_08_020015 }} 198 | RHEL_08_020016: {{ rhel_08_020016 }} 199 | RHEL_08_020017: {{ rhel_08_020017 }} 200 | RHEL_08_020018: {{ rhel_08_020018 }} 201 | RHEL_08_020019: {{ rhel_08_020019 }} 202 | RHEL_08_020020: {{ rhel_08_020020 }} 203 | RHEL_08_020021: {{ rhel_08_020021 }} 204 | RHEL_08_020022: {{ rhel_08_020022 }} 205 | RHEL_08_020023: {{ rhel_08_020023 }} 206 | RHEL_08_020025: {{ rhel_08_020025 }} 207 | RHEL_08_020026: {{ rhel_08_020026 }} 208 | RHEL_08_020027: {{ rhel_08_020027 }} 209 | RHEL_08_020028: {{ rhel_08_020028 }} 210 | RHEL_08_020030: {{ rhel_08_020030 }} 211 | RHEL_08_020031: {{ rhel_08_020031 }} 212 | RHEL_08_020032: {{ rhel_08_020032 }} 213 | RHEL_08_020035: {{ rhel_08_020035 }} 214 | RHEL_08_020050: {{ rhel_08_020050 }} 215 | RHEL_08_020060: {{ rhel_08_020060 }} 216 | RHEL_08_020080: {{ rhel_08_020080 }} 217 | RHEL_08_020081: {{ rhel_08_020081 }} 218 | RHEL_08_020082: {{ rhel_08_020082 }} 219 | RHEL_08_020090: {{ rhel_08_020090 }} # TODO 220 | RHEL_08_020100: {{ rhel_08_020100 }} 221 | RHEL_08_020101: {{ rhel_08_020101 }} 222 | RHEL_08_020102: {{ rhel_08_020102 }} 223 | RHEL_08_020103: {{ rhel_08_020103 }} 224 | RHEL_08_020104: {% if ansible_facts['distribution_version'] is version('8.4', '>=') %}true{% else %}false{% endif %} # Only runs if 8.4 or greater 225 | RHEL_08_020110: {{ rhel_08_020110 }} 226 | RHEL_08_020120: {{ rhel_08_020120 }} 227 | RHEL_08_020130: {{ rhel_08_020130 }} 228 | RHEL_08_020140: {{ rhel_08_020140 }} 229 | RHEL_08_020150: {{ rhel_08_020150 }} 230 | RHEL_08_020160: {{ rhel_08_020160 }} 231 | RHEL_08_020170: {{ rhel_08_020170 }} 232 | RHEL_08_020180: {{ rhel_08_020180 }} 233 | RHEL_08_020190: {{ rhel_08_020190 }} 234 | RHEL_08_020200: {{ rhel_08_020200 }} 235 | RHEL_08_020210: {{ rhel_08_020210 }} 236 | RHEL_08_020230: {{ rhel_08_020230 }} 237 | RHEL_08_020231: {{ rhel_08_020231 }} 238 | RHEL_08_020240: {{ rhel_08_020240 }} 239 | RHEL_08_020250: {{ rhel_08_020250 }} 240 | RHEL_08_020260: {{ rhel_08_020260 }} 241 | RHEL_08_020270: {{ rhel_08_020270 }} 242 | RHEL_08_020280: {{ rhel_08_020280 }} 243 | RHEL_08_020290: {{ rhel_08_020290 }} 244 | RHEL_08_020300: {{ rhel_08_020300 }} 245 | RHEL_08_020310: {{ rhel_08_020310 }} 246 | RHEL_08_020320: {{ rhel_08_020320 }} 247 | RHEL_08_020350: {{ rhel_08_020350 }} 248 | RHEL_08_020351: {{ rhel_08_020351 }} 249 | RHEL_08_020352: {{ rhel_08_020352 }} 250 | RHEL_08_020353: {{ rhel_08_020353 }} 251 | RHEL_08_030000: {{ rhel_08_030000 }} 252 | RHEL_08_030010: {{ rhel_08_030010 }} 253 | RHEL_08_030020: {{ rhel_08_030020 }} 254 | RHEL_08_030030: {{ rhel_08_030030 }} 255 | RHEL_08_030040: {{ rhel_08_030040 }} 256 | RHEL_08_030060: {{ rhel_08_030060 }} 257 | RHEL_08_030061: {{ rhel_08_030061 }} 258 | RHEL_08_030062: {{ rhel_08_030062 }} 259 | RHEL_08_030070: {{ rhel_08_030070 }} 260 | RHEL_08_030080: {{ rhel_08_030080 }} 261 | RHEL_08_030090: {{ rhel_08_030090 }} 262 | RHEL_08_030100: {{ rhel_08_030100 }} 263 | RHEL_08_030110: {{ rhel_08_030110 }} 264 | RHEL_08_030120: {{ rhel_08_030120 }} 265 | RHEL_08_030121: {{ rhel_08_030121 }} 266 | RHEL_08_030122: {{ rhel_08_030122 }} 267 | RHEL_08_030130: {{ rhel_08_030130 }} 268 | RHEL_08_030140: {{ rhel_08_030140 }} 269 | RHEL_08_030150: {{ rhel_08_030150 }} 270 | RHEL_08_030160: {{ rhel_08_030160 }} 271 | RHEL_08_030170: {{ rhel_08_030170 }} 272 | RHEL_08_030171: {{ rhel_08_030171 }} 273 | RHEL_08_030172: {{ rhel_08_030172 }} 274 | RHEL_08_030180: {{ rhel_08_030180 }} 275 | RHEL_08_030181: {{ rhel_08_030181 }} 276 | RHEL_08_030190: {{ rhel_08_030190 }} 277 | RHEL_08_030200: {{ rhel_08_030200 }} 278 | RHEL_08_030250: {{ rhel_08_030250 }} 279 | RHEL_08_030260: {{ rhel_08_030260 }} 280 | RHEL_08_030280: {{ rhel_08_030280 }} 281 | RHEL_08_030290: {{ rhel_08_030290 }} 282 | RHEL_08_030300: {{ rhel_08_030300 }} 283 | RHEL_08_030301: {{ rhel_08_030301 }} 284 | RHEL_08_030302: {{ rhel_08_030302 }} 285 | RHEL_08_030310: {{ rhel_08_030310 }} 286 | RHEL_08_030311: {{ rhel_08_030311 }} 287 | RHEL_08_030312: {{ rhel_08_030312 }} 288 | RHEL_08_030313: {{ rhel_08_030313 }} 289 | RHEL_08_030314: {{ rhel_08_030314 }} 290 | RHEL_08_030315: {{ rhel_08_030315 }} 291 | RHEL_08_030316: {{ rhel_08_030316 }} 292 | RHEL_08_030317: {{ rhel_08_030317 }} 293 | RHEL_08_030320: {{ rhel_08_030320 }} 294 | RHEL_08_030330: {{ rhel_08_030330 }} 295 | RHEL_08_030340: {{ rhel_08_030340 }} 296 | RHEL_08_030350: {{ rhel_08_030350 }} 297 | RHEL_08_030360: {{ rhel_08_030360 }} 298 | RHEL_08_030361: {{ rhel_08_030361 }} 299 | RHEL_08_030370: {{ rhel_08_030370 }} 300 | RHEL_08_030390: {{ rhel_08_030390 }} 301 | RHEL_08_030400: {{ rhel_08_030400 }} 302 | RHEL_08_030410: {{ rhel_08_030410 }} 303 | RHEL_08_030420: {{ rhel_08_030420 }} 304 | RHEL_08_030480: {{ rhel_08_030480 }} 305 | RHEL_08_030490: {{ rhel_08_030490 }} 306 | RHEL_08_030550: {{ rhel_08_030550 }} 307 | RHEL_08_030560: {{ rhel_08_030560 }} 308 | RHEL_08_030570: {{ rhel_08_030570 }} 309 | RHEL_08_030580: {{ rhel_08_030580 }} 310 | RHEL_08_030590: {{ rhel_08_030590 }} 311 | RHEL_08_030600: {{ rhel_08_030600 }} 312 | RHEL_08_030610: {{ rhel_08_030610 }} 313 | RHEL_08_030620: {{ rhel_08_030620 }} 314 | RHEL_08_030630: {{ rhel_08_030630 }} 315 | RHEL_08_030640: {{ rhel_08_030640 }} 316 | RHEL_08_030650: {{ rhel_08_030650 }} 317 | RHEL_08_030660: {{ rhel_08_030660 }} 318 | RHEL_08_030670: {{ rhel_08_030670 }} 319 | RHEL_08_030680: {{ rhel_08_030680 }} 320 | RHEL_08_030690: {{ rhel_08_030090 }} 321 | RHEL_08_030700: {{ rhel_08_030700 }} 322 | RHEL_08_030710: {{ rhel_08_030710 }} 323 | RHEL_08_030720: {{ rhel_08_030720 }} 324 | RHEL_08_030730: {{ rhel_08_030730 }} 325 | RHEL_08_030731: {{ rhel_08_030731 }} 326 | RHEL_08_030740: {{ rhel_08_030740 }} 327 | RHEL_08_040001: {{ rhel_08_040001 }} 328 | RHEL_08_040002: {{ rhel_08_040002 }} 329 | RHEL_08_040020: {{ rhel_08_040020 }} 330 | RHEL_08_040030: {{ rhel_08_040030 }} 331 | RHEL_08_040070: {{ rhel_08_040070 }} 332 | RHEL_08_040080: {{ rhel_08_040080 }} 333 | RHEL_08_040090: {{ rhel_08_040090 }} 334 | RHEL_08_040100: {{ rhel_08_040100 }} 335 | RHEL_08_040101: {{ rhel_08_040101 }} 336 | RHEL_08_040110: {{ rhel_08_040110 }} 337 | RHEL_08_040111: {{ rhel_08_040111 }} 338 | RHEL_08_040120: {{ rhel_08_040120 }} 339 | RHEL_08_040121: {{ rhel_08_040121 }} 340 | RHEL_08_040122: {{ rhel_08_040122 }} 341 | RHEL_08_040123: {{ rhel_08_040123 }} 342 | RHEL_08_040124: {{ rhel_08_040124 }} 343 | RHEL_08_040125: {{ rhel_08_040125 }} 344 | RHEL_08_040126: {{ rhel_08_040126 }} 345 | RHEL_08_040127: {{ rhel_08_040127 }} 346 | RHEL_08_040128: {{ rhel_08_040128 }} 347 | RHEL_08_040129: {{ rhel_08_040129 }} 348 | RHEL_08_040130: {{ rhel_08_040130 }} 349 | RHEL_08_040131: {{ rhel_08_040131 }} 350 | RHEL_08_040132: {{ rhel_08_040132 }} 351 | RHEL_08_040133: {{ rhel_08_040133 }} 352 | RHEL_08_040134: {{ rhel_08_040134 }} 353 | RHEL_08_040135: {{ rhel_08_040135 }} 354 | RHEL_08_040136: {{ rhel_08_040136 }} 355 | RHEL_08_040137: {{ rhel_08_040137 }} 356 | RHEL_08_040139: {{ rhel_08_040139 }} 357 | RHEL_08_040140: {{ rhel_08_040140 }} 358 | RHEL_08_040141: {{ rhel_08_040141 }} 359 | RHEL_08_040150: {{ rhel_08_040150 }} 360 | RHEL_08_040159: {{ rhel_08_040159 }} 361 | RHEL_08_040160: {{ rhel_08_040160 }} 362 | RHEL_08_040161: {{ rhel_08_040161 }} 363 | RHEL_08_040180: {{ rhel_08_040180 }} 364 | RHEL_08_040209: {{ rhel_08_040209 }} 365 | RHEL_08_040210: {{ rhel_08_040210 }} 366 | RHEL_08_040220: {{ rhel_08_040220 }} 367 | RHEL_08_040230: {{ rhel_08_040230 }} 368 | RHEL_08_040239: {{ rhel_08_040239 }} 369 | RHEL_08_040240: {{ rhel_08_040240 }} 370 | RHEL_08_040249: {{ rhel_08_040249 }} 371 | RHEL_08_040250: {{ rhel_08_040250 }} 372 | RHEL_08_040259: {{ rhel_08_040259 }} 373 | RHEL_08_040260: {{ rhel_08_040260 }} 374 | RHEL_08_040261: {{ rhel_08_040261 }} 375 | RHEL_08_040262: {{ rhel_08_040262 }} 376 | RHEL_08_040270: {{ rhel_08_040270 }} 377 | RHEL_08_040279: {{ rhel_08_040279 }} 378 | RHEL_08_040280: {{ rhel_08_040280 }} 379 | RHEL_08_040281: {{ rhel_08_040281 }} 380 | RHEL_08_040282: {{ rhel_08_040282 }} 381 | RHEL_08_040283: {{ rhel_08_040283 }} 382 | RHEL_08_040284: {{ rhel_08_040284 }} 383 | RHEL_08_040285: {{ rhel_08_040285 }} 384 | RHEL_08_040286: {{ rhel_08_040286 }} 385 | RHEL_08_040290: {{ rhel_08_040290 }} 386 | RHEL_08_040320: {{ rhel_08_040320 }} 387 | RHEL_08_040321: {{ rhel_08_040321 }} 388 | RHEL_08_040330: {{ rhel_08_040330 }} 389 | RHEL_08_040340: {{ rhel_08_040340 }} 390 | RHEL_08_040341: {{ rhel_08_040341 }} 391 | RHEL_08_040342: {{ rhel_08_040342 }} 392 | RHEL_08_040350: {{ rhel_08_040350 }} 393 | RHEL_08_040370: {{ rhel_08_040370 }} 394 | RHEL_08_040380: {{ rhel_08_040380 }} 395 | RHEL_08_040390: {{ rhel_08_040390 }} 396 | RHEL_08_040400: {{ rhel_08_040400 }} 397 | 398 | # Cat 3 controls 399 | RHEL_08_010171: {{ rhel_08_010171 }} 400 | RHEL_08_010292: {{ rhel_08_010292 }} 401 | RHEL_08_010375: {{ rhel_08_010375 }} 402 | RHEL_08_010376: {{ rhel_08_010376 }} 403 | RHEL_08_010440: {{ rhel_08_010440 }} 404 | RHEL_08_010471: {% if ansible_facts['distribution_version'] is version('8.4', '>=') %}false{% else %}true{% endif %} # Only runs if 8.3 or less 405 | RHEL_08_010540: {{ rhel_08_010540 }} 406 | RHEL_08_010541: {{ rhel_08_010541 }} 407 | RHEL_08_010542: {{ rhel_08_010542 }} 408 | RHEL_08_020024: {{ rhel_08_020024 }} 409 | RHEL_08_020340: {{ rhel_08_020340 }} 410 | RHEL_08_030063: {{ rhel_08_030063 }} 411 | RHEL_08_030601: {{ rhel_08_030601 }} 412 | RHEL_08_030602: {{ rhel_08_030602 }} 413 | RHEL_08_030603: {{ rhel_08_030603 }} 414 | RHEL_08_030741: {{ rhel_08_030741 }} 415 | RHEL_08_030742: {{ rhel_08_030742 }} 416 | RHEL_08_040004: {{ rhel_08_040004 }} 417 | RHEL_08_040021: {{ rhel_08_040021 }} 418 | RHEL_08_040022: {{ rhel_08_040022 }} 419 | RHEL_08_040023: {{ rhel_08_040023 }} 420 | RHEL_08_040024: {{ rhel_08_040024 }} 421 | RHEL_08_040025: {{ rhel_08_040025 }} 422 | RHEL_08_040026: {{ rhel_08_040026 }} 423 | RHEL_08_040300: {{ rhel_08_040300 }} 424 | RHEL_08_040310: {{ rhel_08_040310 }} 425 | 426 | # Variables 427 | 428 | rhel8stig_password_hash: {{ rhel8stig_bootloader_password_hash }} 429 | rhel8stig_boot_superuser: {{ rhel8stig_boot_superuser }} 430 | 431 | # RHEL_08_101120 & Auditd controls 432 | MIN_UID: {{ rhel8stig_interactive_uid_start }} 433 | MAX_UID: {{ rhel8stig_interactive_uid_stop }} 434 | 435 | 436 | # RHEL_08_010040-010050-010060 437 | rhel8stig_banner_file: /etc/issue 438 | rhel8stig_logon_banner: 439 | You are accessing a U.S. Government (USG) Information System (IS) that is provided for USG-authorized use only. 440 | By using this IS (which includes any device attached to this IS), you consent to the following conditions 441 | -The USG routinely intercepts and monitors communications on this IS for purposes including, but not limited to, penetration testing, COMSEC monitoring, network operations and defense, personnel misconduct (PM), law enforcement (LE), and counterintelligence (CI) investigations. 442 | -At any time, the USG may inspect and seize data stored on this IS. 443 | -Communications using, or data stored on, this IS are not private, are subject to routine monitoring, interception, and search, and may be disclosed or used for any USG-authorized purpose. 444 | -This IS includes security measures (e.g., authentication and access controls) to protect USG interests--not for your personal benefit or privacy. 445 | -Notwithstanding the above, using this IS does not constitute consent to PM, LE or CI investigative searching or monitoring of the content of privileged communications, or work product, related to personal representation or services by attorneys, psychotherapists, or clergy, and their assistants. Such communications and work product are private and confidential. See User Agreement for details. 446 | 447 | # RHEL_08_010680 to change if using hostfile only - seperate checks 448 | rhel8stig_uses_dns: true 449 | 450 | # RHEL_08_010360 if run via ansible it is placed in cron.d setting as manually set in cron.daily 451 | rhel8stig_aide_cron_file: /etc/cron.d/aide 452 | 453 | # RHEL_08_200027 &28 454 | rhel8stig_pam_faillock_dir: {{ rhel8stig_pam_faillock.dir }} 455 | 456 | # RHEL_08_020035 457 | rhel_08_020035_idlesessiontimeout: {{ rhel_08_020035_idlesessiontimeout }} 458 | 459 | # RHEL_08_030040 - Options are SYSLOG, SINGLE, and HALT to fit STIG standards 460 | rhel8stig_auditd_disk_error_action: {{ rhel8stig_auditd_disk_error_action }} 461 | 462 | # RHEL_08_030050 - Options are SYSLOG or KEEP_LOGS to fit STIG standards 463 | rhel8stig_auditd_max_log_file_action: {{ rhel8stig_auditd_max_log_file_action }} 464 | 465 | # RHEL_08_030060 - Options are SYSLOG, HALT, and SINGLE to fit STIG standards 466 | rhel8stig_auditd_disk_full_action: {{ rhel8stig_auditd_disk_full_action }} 467 | 468 | # RHEL_08_030690 if using remote syslog server 469 | rhel8stig_remotelog_server: {{ rhel8stig_remotelog_server.server }} 470 | rhel8stig_remotelog_port: {{ rhel8stig_remotelog_server.port }} 471 | rhel8stig_remotelog_protocol: '{{ rhel8stig_remotelog_server.protocol }}' 472 | 473 | # RHEL_08_040137 474 | python_bin: {{ ansible_python.executable }} 475 | -------------------------------------------------------------------------------- /templates/audit/99_auditd.rules.j2: -------------------------------------------------------------------------------- 1 | # This template will set all of the auditd configurations via a handler in the role in one task instead of individually 2 | {% if rhel_08_030000 %} 3 | -a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -k execpriv 4 | -a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k execpriv 5 | -a always,exit -F arch=b32 -S execve -C gid!=egid -F egid=0 -k execpriv 6 | -a always,exit -F arch=b64 -S execve -C gid!=egid -F egid=0 -k execpriv 7 | {% endif %} 8 | {% if rhel_08_030190 %} 9 | -a always,exit -F path=/usr/bin/su -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-priv_change 10 | {% endif %} 11 | {% if rhel_08_030200 %} 12 | -a always,exit -F arch=b32 -S setxattr,fsetxattr,lsetxattr,removexattr,fremovexattr,lremovexattr -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_mod 13 | -a always,exit -F arch=b64 -S setxattr,fsetxattr,lsetxattr,removexattr,fremovexattr,lremovexattr -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_mod 14 | -a always,exit -F arch=b32 -S setxattr,fsetxattr,lsetxattr,removexattr,fremovexattr,lremovexattr -F auid=0 -k perm_mod 15 | -a always,exit -F arch=b64 -S setxattr,fsetxattr,lsetxattr,removexattr,fremovexattr,lremovexattr -F auid=0 -k perm_mod 16 | {% endif %} 17 | {% if rhel_08_030250 %} 18 | -a always,exit -F path=/usr/bin/chage -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-chage 19 | {% endif %} 20 | {% if rhel_08_030260 %} 21 | -a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_mod 22 | {% endif %} 23 | {% if rhel_08_030280 %} 24 | -a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-ssh 25 | {% endif %} 26 | {% if rhel_08_030290 %} 27 | -a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-passwd 28 | {% endif %} 29 | {% if rhel_08_030300 %} 30 | -a always,exit -F path=/usr/bin/mount -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-mount 31 | {% endif %} 32 | {% if rhel_08_030301 %} 33 | -a always,exit -F path=/usr/bin/umount -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-mount 34 | {% endif %} 35 | {% if rhel_08_030302 %} 36 | -a always,exit -F arch=b32 -S mount -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-mount 37 | -a always,exit -F arch=b64 -S mount -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-mount 38 | {% endif %} 39 | {% if rhel_08_030310 %} 40 | -a always,exit -F path=/usr/sbin/unix_update -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-unix-update 41 | {% endif %} 42 | {% if rhel_08_030311 %} 43 | -a always,exit -F path=/usr/sbin/postdrop -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-unix-update 44 | {% endif %} 45 | {% if rhel_08_030312 %} 46 | -a always,exit -F path=/usr/sbin/postqueue -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-unix-update 47 | {% endif %} 48 | {% if rhel_08_030313 %} 49 | -a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-unix-update 50 | {% endif %} 51 | {% if rhel_08_030314 %} 52 | -a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-unix-update 53 | {% endif %} 54 | {% if rhel_08_030315 %} 55 | -a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-unix-update 56 | {% endif %} 57 | {% if rhel_08_030316 %} 58 | -a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-unix-update 59 | {% endif %} 60 | {% if rhel_08_030317 %} 61 | -a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-unix-update 62 | {% endif %} 63 | {% if rhel_08_030320 %} 64 | -a always,exit -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-ssh 65 | {% endif %} 66 | {% if rhel_08_030330 %} 67 | -a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_mod 68 | {% endif %} 69 | {% if rhel_08_030340 %} 70 | -a always,exit -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-pam_timestamp_check 71 | {% endif %} 72 | {% if rhel_08_030350 %} 73 | -a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k priv_cmd 74 | {% endif %} 75 | {% if rhel_08_030360 %} 76 | -a always,exit -F arch=b32 -S init_module,finit_module -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k module_chng 77 | -a always,exit -F arch=b64 -S init_module,finit_module -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k module_chng 78 | {% endif %} 79 | {% if rhel_08_030361 %} 80 | -a always,exit -F arch=b32 -S rename,unlink,rmdir,renameat,unlinkat -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k delete 81 | -a always,exit -F arch=b64 -S rename,unlink,rmdir,renameat,unlinkat -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k delete 82 | {% endif %} 83 | {% if rhel_08_030370 %} 84 | -a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-gpasswd 85 | {% endif %} 86 | {% if rhel_08_030390 %} 87 | -a always,exit -F arch=b32 -S delete_module -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k module_chng 88 | -a always,exit -F arch=b64 -S delete_module -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k module_chng 89 | {% endif %} 90 | {% if rhel_08_030400 %} 91 | -a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-crontab 92 | {% endif %} 93 | {% if rhel_08_030410 %} 94 | -a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k priv_cmd 95 | {% endif %} 96 | {% if rhel_08_030420 %} 97 | -a always,exit -F arch=b32 -S truncate,ftruncate,creat,open,openat,open_by_handle_at -F exit=-EPERM -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_access 98 | -a always,exit -F arch=b64 -S truncate,ftruncate,creat,open,openat,open_by_handle_at -F exit=-EPERM -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_access 99 | -a always,exit -F arch=b32 -S truncate,ftruncate,creat,open,openat,open_by_handle_at -F exit=-EACCES -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_access 100 | -a always,exit -F arch=b64 -S truncate,ftruncate,creat,open,openat,open_by_handle_at -F exit=-EACCES -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_access 101 | {% endif %} 102 | {% if rhel_08_030480 %} 103 | -a always,exit -F arch=b32 -S chown,fchown,fchownat,lchown -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_mod 104 | -a always,exit -F arch=b64 -S chown,fchown,fchownat,lchown -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_mod 105 | {% endif %} 106 | {% if rhel_08_030490 %} 107 | -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_mod 108 | -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_mod 109 | {% endif %} 110 | {% if rhel_08_030550 %} 111 | -a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k priv_cmd 112 | {% endif %} 113 | {% if rhel_08_030560 %} 114 | -a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k privileged-usermod 115 | {% endif %} 116 | {% if rhel_08_030570 %} 117 | -a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>={{ rhel8stig_interactive_uid_start }} -F auid!=unset -k perm_mod 118 | {% endif %} 119 | {% if rhel_08_030580 %} 120 | -a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -k modules 121 | {% endif %} 122 | {% if rhel_08_030590 %} 123 | -w {{ rhel8stig_pam_faillock.dir }} -p wa -k logins 124 | {% endif %} 125 | {% if rhel_08_030600 %} 126 | -w /var/log/lastlog -p wa -k logins 127 | {% endif %} 128 | -------------------------------------------------------------------------------- /templates/etc/ansible/compliance_facts.j2: -------------------------------------------------------------------------------- 1 | # STIG Hardening Carried out 2 | # Added as part of ansible-lockdown STIG baseline 3 | # provided by Mindpoint Group - A Tyto Athene Company 4 | 5 | [lockdown_details] 6 | # Benchmark release 7 | Benchmark_release = {{ benchmark }} 8 | Benchmark_version = {{ benchmark_version }} 9 | Benchmark_run_date = {{ '%Y-%m-%d - %H:%M:%S' | ansible.builtin.strftime }} 10 | # If options set (doesn't mean it ran all controls) 11 | cat_1_hardening_enabled = {{ rhel8stig_cat1 }} 12 | cat_2_hardening_enabled = {{ rhel8stig_cat2 }} 13 | cat_3_hardening_enabled = {{ rhel8stig_cat3 }} 14 | 15 | {% if ansible_run_tags | length > 0 %} 16 | # If tags used to stipulate run level 17 | {% if 'rhel8stig_cat1' in ansible_run_tags %} 18 | Cat_1_Server_tag_run = true 19 | {% endif %} 20 | {% if 'rhel8stig_cat2' in ansible_run_tags %} 21 | Cat_2_Server_tag_run = true 22 | {% endif %} 23 | {% if 'rhel8stig_cat3' in ansible_run_tags %} 24 | Cat_3_Server_tag_run = true 25 | {% endif %} 26 | {% endif %} 27 | 28 | [lockdown_audit_details] 29 | {% if run_audit %} 30 | # Audit run 31 | audit_run_date = {{ '%Y-%m-%d - %H:%M:%S' | ansible.builtin.strftime }} 32 | audit_file_local_location = {{ audit_log_dir }} 33 | {% if not audit_only %} 34 | audit_summary = {{ post_audit_results }} 35 | {% endif %} 36 | {% if fetch_audit_output %} 37 | audit_files_centralized_location = {{ audit_output_destination }} 38 | {% endif %} 39 | {% endif %} 40 | -------------------------------------------------------------------------------- /templates/etc_default_grub.j2: -------------------------------------------------------------------------------- 1 | GRUB_TIMEOUT=5 2 | GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)" 3 | GRUB_DEFAULT=saved 4 | GRUB_DISABLE_SUBMENU=true 5 | GRUB_TERMINAL_OUTPUT="console" 6 | GRUB_CMDLINE_LINUX="{{ grub_cmdline_linux }}" 7 | {#{% for param, value in ansible_cmdline.iteritems() 8 | %}{% if param not in blacklist %} {{ param }}{% if value is string %}={{ value }}{% 9 | endif %}{% endif %}{% endfor %}"#} 10 | GRUB_DISABLE_RECOVERY="true" 11 | -------------------------------------------------------------------------------- /templates/resolv.conf.j2: -------------------------------------------------------------------------------- 1 | {% if rhel8_stig_resolv_domain is defined %} 2 | domain {{ rhel8_stig_resolv_domain }} 3 | {% endif %} 4 | {% if rhel8_stig_resolv_search is iterable %} 5 | search {{ rhel8_stig_resolv_search | join(' ') }} 6 | {% endif %} 7 | {% if rhel8stig_dns_servers is iterable %} 8 | {% for server in rhel8stig_dns_servers %} 9 | nameserver {{ server }} 10 | {% endfor %} 11 | {% endif %} 12 | {% if rhel8_stig_resolv_options is iterable %} 13 | options {{ rhel8_stig_resolv_options | join(' ') }} 14 | {% endif %} 15 | -------------------------------------------------------------------------------- /test_plugins/rhel8_stig_ansible_backport.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (c) 2016, Ansible, Inc 4 | # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 | 6 | from __future__ import (absolute_import, division, print_function) 7 | 8 | def contains(seq, value): 9 | '''Opposite of the ``in`` test, allowing use as a test in filters like ``selectattr`` 10 | 11 | .. versionadded:: 2.8 12 | ''' 13 | return value in seq 14 | 15 | class TestModule: 16 | ''' Ansible math jinja2 tests ''' 17 | 18 | def tests(self): 19 | return { 20 | # set theory 21 | 'contains': contains, 22 | } 23 | -------------------------------------------------------------------------------- /test_plugins/rhel8_stig_jinja_compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (c) 2017, the Jinja Team 4 | # BSD 3-Clause "New" or "Revised" License (see https://opensource.org/licenses/BSD-3-Clause) 5 | 6 | from __future__ import (absolute_import, division, print_function) 7 | __metaclass__ = type 8 | 9 | import operator 10 | 11 | def test_in(value, seq): 12 | """Check if value is in seq. 13 | Copied from Jinja 2.10 https://github.com/pallets/jinja/pull/665 14 | 15 | .. versionadded:: 2.10 16 | """ 17 | return value in seq 18 | 19 | 20 | class TestModule: 21 | ''' Tests from jinja 2.10 for compat with older jinja2 on RHEL 7. ''' 22 | 23 | def tests(self): 24 | return { 25 | 'in': test_in, 26 | '==': operator.eq, 27 | 'eq': operator.eq, 28 | 'equalto': operator.eq, 29 | '!=': operator.ne, 30 | 'ne': operator.ne, 31 | '>': operator.gt, 32 | 'gt': operator.gt, 33 | 'greaterthan': operator.gt, 34 | 'ge': operator.ge, 35 | '>=': operator.ge, 36 | '<': operator.lt, 37 | 'lt': operator.lt, 38 | 'lessthan': operator.lt, 39 | '<=': operator.le, 40 | 'le': operator.le, 41 | } 42 | -------------------------------------------------------------------------------- /vars/AlmaLinux.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | gpg_keys: 4 | - name: 'AlmaLinux' 5 | packager: "packager@almalinux.org" 6 | fingerprint: "5E9B 8F56 17B5 066C E920 57C3 488F CF7C 3ABB 34F8" 7 | 8 | gpg_package: almalinux-release 9 | rpm_gpg_key: /etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux 10 | -------------------------------------------------------------------------------- /vars/OracleLinux.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | gpg_keys: 4 | - name: 'Oracle OSS group' 5 | packager: "build@oss.oracle.com" 6 | fingerprint: "76FD 3DB1 3AB6 7410 B89D B10E 8256 2EA9 AD98 6DA3" 7 | 8 | gpg_package: oraclelinux-release 9 | rpm_gpg_key: /etc/pki/rpm-gpg/RPM-GPG-KEY-oracle 10 | -------------------------------------------------------------------------------- /vars/RedHat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | gpg_keys: 4 | - name: 'release key 2' 5 | packager: 'security@redhat.com' 6 | fingerprint: '567E 347A D004 4ADE 55BA 8A5F 199E 2F91 FD43 1D51' 7 | 8 | - name: 'auxiliary key' 9 | packager: 'security@redhat.com' 10 | fingerprint: '6A6A A7C9 7C88 90AE C6AE BFE2 F76F 66C3 D408 2792' 11 | 12 | gpg_package: redhat-release 13 | rpm_gpg_key: /etc/pki/rpm-gpg/RPM-GPG-KEY-{{ ansible_distribution | lower }}-release 14 | -------------------------------------------------------------------------------- /vars/Rocky.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | gpg_keys: 4 | - name: 'Release Engineering' 5 | packager: "infrastructure@rockylinux.org" 6 | fingerprint: "7051 C470 A929 F454 CEBE 37B7 15AF 5DAC 6D74 5A60" 7 | 8 | gpg_package: rocky-gpg-keys 9 | rpm_gpg_key: /etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial 10 | -------------------------------------------------------------------------------- /vars/audit.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | #### Audit Configuration Settings #### 4 | 5 | # Timeout for those cmds that take longer to run where timeout set 6 | audit_cmd_timeout: 120000 7 | 8 | # if get_audit_binary_method == download change accordingly 9 | audit_bin_url: "https://github.com/goss-org/goss/releases/download/{{ audit_bin_version.release }}/goss-linux-" 10 | 11 | ### Goss Audit Benchmark file ### 12 | ## managed by the control audit_content 13 | # git 14 | audit_file_git: "https://github.com/ansible-lockdown/{{ benchmark }}-Audit.git" 15 | audit_git_version: "benchmark_{{ benchmark_version }}_rh8" 16 | 17 | ## Goss configuration information 18 | # Where the goss audit configuration will be stored - NOTE benchmark-audit is expected 19 | audit_conf_dir: "{{ audit_conf_dest | default('/opt') }}/{{ benchmark }}-Audit" 20 | 21 | # If changed these can affect other products 22 | pre_audit_outfile: "{{ audit_log_dir }}/{{ ansible_facts.hostname }}-{{ benchmark }}-{{ benchmark_version }}_pre_scan_{{ ansible_facts.date_time.epoch }}.{{ audit_format }}" 23 | post_audit_outfile: "{{ audit_log_dir }}/{{ ansible_facts.hostname }}-{{ benchmark }}-{{ benchmark_version }}_post_scan_{{ ansible_facts.date_time.epoch }}.{{ audit_format }}" 24 | 25 | ## The following should not need changing 26 | 27 | ### Audit binary settings ### 28 | audit_bin_version: 29 | release: v0.4.4 30 | AMD64_checksum: 'sha256:1c4f54b22fde9d4d5687939abc2606b0660a5d14a98afcd09b04b793d69acdc5' 31 | audit_bin_path: /usr/local/bin/ 32 | audit_bin: "{{ audit_bin_path }}goss" 33 | audit_format: json 34 | 35 | audit_vars_path: "{{ audit_conf_dir }}/vars/{{ ansible_facts.hostname }}.yml" 36 | audit_results: | 37 | The{% if not audit_only %} pre remediation{% endif %} audit results are: {{ pre_audit_results }} 38 | {% if not audit_only %}The post remediation audit results are: {{ post_audit_results }}{% endif %} 39 | 40 | Full breakdown can be found in {{ audit_log_dir }} 41 | -------------------------------------------------------------------------------- /vars/is_container.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Container vars file 4 | 5 | rhel8stig_ssh_required: false 6 | 7 | # tmux 8 | rhel_08_020039: false 9 | rhel_08_020040: false 10 | rhel_08_020041: false 11 | rhel_08_020070: false 12 | 13 | # auditd 14 | rhel_08_010560: false 15 | rhel_08_030000: false 16 | rhel_08_030020: false 17 | rhel_08_030040: false 18 | # rhel_08_030050: false 19 | rhel_08_030060: false 20 | rhel_08_030061: false 21 | rhel_08_030062: false 22 | rhel_08_030070: false 23 | rhel_08_030080: false 24 | rhel_08_030090: false 25 | rhel_08_030100: false 26 | rhel_08_030110: false 27 | rhel_08_030120: false 28 | rhel_08_030121: false 29 | rhel_08_030122: false 30 | rhel_08_030130: false 31 | rhel_08_030140: false 32 | rhel_08_030150: false 33 | rhel_08_030160: false 34 | rhel_08_030170: false 35 | rhel_08_030171: false 36 | rhel_08_030172: false 37 | rhel_08_030180: false 38 | rhel_08_030181: false 39 | rhel_08_030190: false 40 | rhel_08_030200: false 41 | rhel_08_030210: false 42 | rhel_08_030220: false 43 | rhel_08_030230: false 44 | rhel_08_030240: false 45 | rhel_08_030250: false 46 | rhel_08_030260: false 47 | # rhel_08_030270: false 48 | rhel_08_030280: false 49 | rhel_08_030290: false 50 | rhel_08_030300: false 51 | rhel_08_030301: false 52 | rhel_08_030302: false 53 | rhel_08_030310: false 54 | rhel_08_030311: false 55 | rhel_08_030312: false 56 | rhel_08_030313: false 57 | rhel_08_030314: false 58 | rhel_08_030315: false 59 | rhel_08_030316: false 60 | rhel_08_030317: false 61 | rhel_08_030320: false 62 | rhel_08_030330: false 63 | rhel_08_030340: false 64 | rhel_08_030350: false 65 | rhel_08_030360: false 66 | rhel_08_030361: false 67 | rhel_08_030370: false 68 | rhel_08_030390: false 69 | rhel_08_030400: false 70 | rhel_08_030410: false 71 | rhel_08_030420: false 72 | rhel_08_030480: false 73 | rhel_08_030490: false 74 | rhel_08_030550: false 75 | rhel_08_030560: false 76 | rhel_08_030570: false 77 | rhel_08_030580: false 78 | rhel_08_030590: false 79 | rhel_08_030600: false 80 | rhel_08_030610: false 81 | rhel_08_030620: false 82 | rhel_08_030630: false 83 | rhel_08_030640: false 84 | rhel_08_030660: false 85 | # rhel_08_030690: false # Also rsyslog 86 | rhel_08_030700: false 87 | # rhel_08_030710: false # Also rsyslog 88 | # rhel_08_030720: false # Also rsyslog 89 | rhel_08_030730: false 90 | rhel_08_030731: false 91 | # rhel_08_010542: false # Also Rsyslog 92 | rhel_08_030063: false 93 | # rhel_08_030602: false # Also grub 94 | 95 | # rsyslog 96 | rhel_08_010070: false 97 | rhel_08_010561: false 98 | rhel_08_010210: false 99 | rhel_08_010220: false 100 | rhel_08_010230: false 101 | rhel_08_030010: false 102 | rhel_08_030670: false 103 | rhel_08_030680: false 104 | rhel_08_030690: false 105 | rhel_08_030710: false 106 | rhel_08_030720: false 107 | 108 | # selinux 109 | rhel_08_010170: false 110 | rhel_08_010450: false 111 | rhel_08_020027: false 112 | rhel_08_020028: false 113 | 114 | ## mounts 115 | # /tmp 116 | rhel_08_010543: false 117 | rhel_08_040123: false 118 | rhel_08_040124: false 119 | rhel_08_040125: false 120 | # /var/log 121 | rhel_08_040126: false 122 | rhel_08_040127: false 123 | rhel_08_040128: false 124 | rhel_08_010541: false 125 | # /var/tmp 126 | rhel_08_010544: false 127 | rhel_08_040132: false 128 | rhel_08_040133: false 129 | rhel_08_040134: false 130 | # /var/log/audit 131 | rhel_08_040129: false 132 | rhel_08_040130: false 133 | rhel_08_040131: false 134 | rhel_08_010542: false 135 | # /home 136 | rhel_08_010570: false 137 | rhel_08_010590: false 138 | rhel_08_010800: false 139 | # /boot 140 | rhel_08_010571: false 141 | # /boot/efi 142 | rhel_08_010572: false 143 | # 144 | rhel_08_010580: false 145 | # /media 146 | rhel_08_010600: false 147 | rhel_08_010610: false 148 | # /mnt 149 | rhel_08_010620: false 150 | # NFS 151 | rhel_08_010630: false 152 | rhel_08_010640: false 153 | rhel_08_010650: false 154 | # /dev/shm 155 | rhel_08_040120: false 156 | rhel_08_040121: false 157 | rhel_08_040122: false 158 | # /var 159 | rhel_08_010540: false 160 | 161 | # firewall 162 | rhel8stig_firewall_service: not_required 163 | rhel_08_040030: false 164 | 165 | # fapolicy 166 | rhel_08_040135: false 167 | rhel_08_040136: false 168 | rhel_08_040137: false 169 | 170 | # grub 171 | rhel_08_010141: false 172 | rhel_08_010149: false 173 | rhel_08_010421: false 174 | rhel_08_010422: false 175 | rhel_08_010423: false 176 | rhel_08_030601: false 177 | rhel_08_030602: false 178 | rhel_08_040004: false 179 | 180 | # modprobe 181 | rhel_08_040021: false 182 | rhel_08_040022: false 183 | rhel_08_040023: false 184 | rhel_08_040024: false 185 | rhel_08_040025: false 186 | rhel_08_040026: false 187 | 188 | # chrony 189 | rhel_08_030740: false 190 | rhel_08_030741: false 191 | rhel_08_030742: false 192 | 193 | # fips 194 | rhel_08_010290: false 195 | rhel_08_010291: false 196 | rhel_08_010293: false 197 | 198 | # aide 199 | rhel_08_010359: false 200 | rhel_08_010360: false 201 | rhel_08_030650: false 202 | rhel_08_040300: false 203 | rhel_08_040310: false 204 | 205 | # sudo 206 | rhel_08_010379: false 207 | rhel_08_010380: false 208 | rhel_08_010381: false 209 | rhel_08_010382: false 210 | rhel_08_010383: false 211 | rhel_08_010384: false 212 | 213 | # Other 214 | rhel_08_010410: false 215 | rhel_08_010472: false 216 | rhel_08_010672: false 217 | rhel_08_010680: false 218 | rhel_08_040111: false 219 | rhel_08_040139: false 220 | rhel_08_040140: false 221 | rhel_08_040141: false 222 | rhel_08_040180: false 223 | rhel_08_040330: false 224 | -------------------------------------------------------------------------------- /vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | rhel8stig_min_ansible_version: 2.11.1 4 | 5 | rhel8stig_dconf_available: "{{ rhel8stig_gui or rhel8stig_dconf_audit.rc == 0 or 6 | rhel8stig_always_configure_dconf }}" 7 | rhel8stig_has_dconf_command: "{{ rhel8stig_gui or rhel8stig_dconf_audit.rc == 0 }}" 8 | 9 | rhel8stig_service_started: "{{ rhel8stig_system_is_chroot | ternary(omit, 'started') }}" 10 | # !!!!!!!!possibly delete 11 | # rhel8stig_systemd_daemon_reload: "{{ not rhel8stig_system_is_chroot }}" 12 | 13 | rhel8stig_sysctl_reload: "{{ not system_is_container }}" 14 | 15 | # these variables are for enabling tasks to run that will be further controled 16 | # by check_mode to prevent the remediation task from making changes as 17 | # requested 18 | rhel8stig_complex: "{{ rhel8stig_complexity_high or rhel8stig_audit_complex }}" 19 | rhel8stig_disruptive: "{{ rhel8stig_disruption_high or rhel8stig_audit_disruptive }}" 20 | 21 | # These vars are made to go in the check_mode property of a task that is 22 | # complex or disruptive, respectively. 23 | # !!!! possibly delete 24 | # rhel8stig_complex_check_mode: "{{ ansible_check_mode or rhel8stig_audit_complex and not rhel8stig_complexity_high }}" 25 | rhel8stig_disruptive_check_mode: "{{ ansible_check_mode or rhel8stig_audit_disruptive and not rhel8stig_disruption_high }}" 26 | 27 | # this allows us to insert a name=value into a line of the format: 28 | # key="name1=value1 name2=value2 nameN=valueN" 29 | rhel8stig_regexp_quoted_params: ^({{ rhel8stig_re_qp_key }})({{ rhel8stig_re_qp_other_params }})({{ 30 | rhel8stig_re_qp_param }}?)({{ rhel8stig_re_qp_other_params }})({{ rhel8stig_re_qp_key_end }}) 31 | rhel8stig_replace_quoted_params: \1\2{{ rhel8stig_re_qp_insert | ternary('', ' ') }}{{ param }}={{ 32 | value }}{{ rhel8stig_re_qp_insert | ternary(' ', '') }}\4\5 33 | 34 | # none of these regexes create capture groups 35 | rhel8stig_re_qp_key: (?:\s*{{ key }}=") 36 | rhel8stig_re_qp_param: (?:{{ rhel8stig_re_qp_insert | ternary('', ' ?') }}{{ 37 | rhel8stig_re_qp_param_start }}{{ param }}=.*?{{ 38 | rhel8stig_re_qp_param_end }}{{ rhel8stig_re_qp_insert | ternary(' ?', '') }}) 39 | rhel8stig_re_qp_other_params: (?:(?!{{ rhel8stig_re_qp_param }}.*).)*{{ 40 | rhel8stig_re_qp_insert | ternary('?', '') }} 41 | rhel8stig_re_qp_param_start: (?<=[" ]) 42 | rhel8stig_re_qp_param_end: (?=[" ]) 43 | rhel8stig_re_qp_key_end: (?:" *) 44 | 45 | # insert the parameter at the beginning or append to the end, default append 46 | rhel8stig_re_qp_insert: "{{ insert | default(not (append | default(true))) }}" 47 | --------------------------------------------------------------------------------