diff --git a/.ansible-lint b/.ansible-lint index 3b7c373..964eb05 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -3,7 +3,21 @@ parseable: true quiet: true skip_list: - - 'package-latest' - - 'risky-shell-pipe' + - 'schema' + - 'no-changed-when' + - 'var-spacing' + - 'fqcn-builtins' + - 'experimental' + - 'name[play]' + - 'name[casing]' + - 'name[template]' + - 'fqcn[action]' + - '204' + - '305' + - '303' + - '403' + - '306' + - '602' + - '208' use_default_rules: true verbosity: 0 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..d3828ea --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,34 @@ +--- +name: Report Issue +about: Create a bug issue ticket to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the Issue** +A clear and concise description of what the bug is. + +**Expected Behavior** +A clear and concise description of what you expected to happen. + +**Actual Behavior** +A clear and concise description of what's happening. + +**Control(s) Affected** +What controls are being affected by the issue + +**Environment (please complete the following information):** + +- branch being used: [e.g. devel] +- Ansible Version: [e.g. 2.10] +- Host Python Version: [e.g. Python 3.7.6] +- Ansible Server Python Version: [e.g. Python 3.7.6] +- Additional Details: + +**Additional Notes** +Anything additional goes here + +**Possible Solution** +Enter a suggested fix here diff --git a/.github/ISSUE_TEMPLATE/feature-request-or-enhancement.md b/.github/ISSUE_TEMPLATE/feature-request-or-enhancement.md new file mode 100644 index 0000000..3908075 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-or-enhancement.md @@ -0,0 +1,22 @@ +--- +name: Feature Request or Enhancement +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +## Feature Request or Enhancement + +- Feature [] +- Enhancement [] + +**Summary of Request** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Suggested Code** +Please provide any code you have in mind to fulfill the request diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 0000000..ad0629e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,18 @@ +--- +name: Question +about: Ask away....... +title: '' +labels: question +assignees: '' + +--- + +**Question** +Pose question here. + +**Environment (please complete the following information):** + +- Ansible Version: [e.g. 2.10] +- Host Python Version: [e.g. Python 3.7.6] +- Ansible Server Python Version: [e.g. Python 3.7.6] +- Additional Details: diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..05dadb6 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,12 @@ +**Overall Review of Changes:** +A general description of the changes made that are being requested for merge + +**Issue Fixes:** +Please list (using linking) any open issues this PR addresses + +**Enhancements:** +Please list any enhancements/features that are not open issue tickets + +**How has this been tested?:** +Please give an overview of how these changes were tested. If they were not please use N/A + diff --git a/.github/workflows/OS.tfvars b/.github/workflows/OS.tfvars new file mode 100644 index 0000000..634512b --- /dev/null +++ b/.github/workflows/OS.tfvars @@ -0,0 +1,9 @@ +#Ami Alma 9 +ami_id = "ami-0845395779540e3cb" +ami_os = "rhel9" +ami_username = "ec2-user" +ami_user_home = "/home/ec2-user" +instance_tags = { + Name = "RHEL9-CIS" + Environment = "lockdown_github_repo_workflow" +} diff --git a/.github/workflows/add_repo_issue_to_gh_project.yml b/.github/workflows/add_repo_issue_to_gh_project.yml deleted file mode 100644 index 80d7344..0000000 --- a/.github/workflows/add_repo_issue_to_gh_project.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- - -name: Add Repo Issue to ALD GH project -on: - issues: - types: - - opened - - reopened - - transferred -jobs: - add-to-project: - runs-on: ubuntu-latest - steps: - - uses: actions/add-to-project@main - with: - project-url: https://github.com/orgs/ansible-lockdown/projects/1 - github-token: ${{ secrets.ALD_GH_PROJECT }} diff --git a/.github/workflows/benchmark_tracking_controller.yml b/.github/workflows/benchmark_tracking_controller.yml deleted file mode 100644 index 039ec0d..0000000 --- a/.github/workflows/benchmark_tracking_controller.yml +++ /dev/null @@ -1,54 +0,0 @@ ---- - -# GitHub schedules all cron jobs in UTC. -# ────────────────────────────────────────────────────────────────────────────── -# Schedule: -# - '0 13 * * *' runs at 13:00 UTC every day. -# - This corresponds to: -# • 9:00 AM Eastern **during Daylight Saving Time** (mid-Mar → early-Nov) -# • 8:00 AM Eastern **during Standard Time** (early-Nov → mid-Mar) -# -# Job routing: -# - call-benchmark-tracker: -# • Runs on manual dispatch, and on pushes to the 'latest' branch. -# - call-monitor-promotions: -# • Runs on schedule or manual dispatch **only in repos named ansible-lockdown/Private-***. -# • Skips automatically in public repos (e.g., Windows-2022-CIS) to avoid false failures. -# -# Defense-in-depth: -# - The called promotion workflow may still keep its own guard to ensure only Private-* repos execute it. - -name: Central Benchmark Orchestrator - -on: - push: - branches: - - latest - schedule: - - cron: '0 13 * * *' # 13:00 UTC → 9 AM ET (DST) / 8 AM ET (Standard Time) - workflow_dispatch: - -jobs: - call-benchmark-tracker: - # Run on manual dispatch OR when 'latest' branch receives a push - if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref_name == 'latest') - name: Start Benchmark Tracker - uses: ansible-lockdown/github_linux_IaC/.github/workflows/benchmark_track.yml@self_hosted - with: - repo_name: ${{ github.repository }} - secrets: - TEAMS_WEBHOOK_URL: ${{ secrets.TEAMS_WEBHOOK_URL }} - BADGE_PUSH_TOKEN: ${{ secrets.BADGE_PUSH_TOKEN }} - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} - - call-monitor-promotions: - # Run on schedule or manual dispatch, but only for Private-* repos - if: (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && startsWith(github.repository, 'ansible-lockdown/Private-') - name: Monitor Promotions and Auto-Promote - uses: ansible-lockdown/github_linux_IaC/.github/workflows/benchmark_promote.yml@self_hosted - with: - repo_name: ${{ github.repository }} - secrets: - TEAMS_WEBHOOK_URL: ${{ secrets.TEAMS_WEBHOOK_URL }} - BADGE_PUSH_TOKEN: ${{ secrets.BADGE_PUSH_TOKEN }} - DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} diff --git a/.github/workflows/devel_pipeline_validation.yml b/.github/workflows/devel_pipeline_validation.yml deleted file mode 100644 index 8fd728a..0000000 --- a/.github/workflows/devel_pipeline_validation.yml +++ /dev/null @@ -1,162 +0,0 @@ ---- - - name: Devel pipeline - - on: # yamllint disable-line rule:truthy - pull_request_target: - types: [opened, reopened, synchronize] - branches: - - devel - - benchmark* - paths: - - '**.yml' - - '**.sh' - - '**.j2' - - '**.ps1' - - '**.cfg' - # Allow manual running of workflow - workflow_dispatch: - - # A workflow run is made up of one or more jobs - # that can run sequentially or in parallel - jobs: - # This will create messages for first time contributers and direct them to the Discord server - welcome: - runs-on: ubuntu-latest - - permissions: - issues: write - pull-requests: write - - steps: - - uses: actions/first-interaction@main - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - issue_message: |- - Congrats on opening your first issue and thank you for taking the time to help improve Ansible-Lockdown! - Please join in the conversation happening on the [Discord Server](https://www.lockdownenterprise.com/discord) as well. - pr_message: |- - Congrats on opening your first pull request and thank you for taking the time to help improve Ansible-Lockdown! - Please join in the conversation happening on the [Discord Server](https://www.lockdownenterprise.com/discord) as well. - - # This workflow contains a single job that tests the playbook - playbook-test: - # The type of runner that the job will run on - runs-on: self-hosted - - # Allow permissions for AWS auth - permissions: - id-token: write - contents: read - pull-requests: read - - env: - ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }} - # Imported as a variable by terraform - TF_VAR_repository: ${{ github.event.repository.name }} - AWS_REGION: "us-east-1" - ANSIBLE_VERSION: ${{ vars.ANSIBLE_RUNNER_VERSION }} - defaults: - run: - shell: bash - working-directory: .github/workflows/github_linux_IaC - # working-directory: .github/workflows - - steps: - - - name: Git clone the lockdown repository to test - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - - - name: If a variable for IAC_BRANCH is set use that branch - working-directory: .github/workflows - run: | - if [ ${{ vars.IAC_BRANCH }} != '' ]; then - echo "IAC_BRANCH=${{ vars.IAC_BRANCH }}" >> $GITHUB_ENV - echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}" - else - echo IAC_BRANCH=main >> $GITHUB_ENV - fi - - # Pull in terraform code for linux servers - - name: Clone GitHub IaC plan - uses: actions/checkout@v4 - with: - repository: ansible-lockdown/github_linux_IaC - path: .github/workflows/github_linux_IaC - ref: ${{ env.IAC_BRANCH }} - - # Uses dedicated restricted role and policy to enable this only for this task - # No credentials are part of github for AWS auth - - name: configure aws credentials - uses: aws-actions/configure-aws-credentials@main - with: - role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }} - role-session-name: ${{ secrets.AWS_ROLE_SESSION }} - aws-region: ${{ env.AWS_REGION }} - - - name: DEBUG - Show IaC files - if: env.ENABLE_DEBUG == 'true' - run: | - echo "OSVAR = $OSVAR" - echo "benchmark_type = $benchmark_type" - pwd - env: - # Imported from GitHub variables this is used to load the relevant OS.tfvars file - OSVAR: ${{ vars.OSVAR }} - benchmark_type: ${{ vars.BENCHMARK_TYPE }} - - - name: Tofu init - id: init - run: tofu init - env: - # Imported from GitHub variables this is used to load the relevant OS.tfvars file - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - - - name: Tofu validate - id: validate - run: tofu validate - env: - # Imported from GitHub variables this is used to load the relevant OS.tfvars file - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - - - name: Tofu apply - id: apply - env: - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} - TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} - run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false - -## Debug Section - - name: DEBUG - Show Ansible hostfile - if: env.ENABLE_DEBUG == 'true' - run: cat hosts.yml - - # Aws deployments taking a while to come up insert sleep or playbook fails - - - name: Sleep to allow system to come up - run: sleep ${{ vars.BUILD_SLEEPTIME }} - - # Run the Ansible playbook - - name: Run_Ansible_Playbook - env: - ANSIBLE_HOST_KEY_CHECKING: "false" - ANSIBLE_DEPRECATION_WARNINGS: "false" - run: | - /opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml - - # Remove test system - User secrets to keep if necessary - - - name: Tofu Destroy - if: always() && env.ENABLE_DEBUG == 'false' - env: - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} - TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} - run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false diff --git a/.github/workflows/export_badges_private.yml b/.github/workflows/export_badges_private.yml deleted file mode 100644 index d316cbf..0000000 --- a/.github/workflows/export_badges_private.yml +++ /dev/null @@ -1,27 +0,0 @@ ---- - -name: Export Private Repo Badges - -# Use different minute offsets with the same hourly pattern: -# Repo Group Suggested Cron Expression Explanation -# Group A 0 */6 * * * Starts at top of hour -# Group B 10 */6 * * * Starts at 10 after -# And So On - -on: - push: - branches: - - latest - schedule: - - cron: '0 */6 * * *' - workflow_dispatch: - -jobs: - export-badges: - if: github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && startsWith(github.repository, 'ansible-lockdown/Private-')) || (github.event_name == 'push' && github.ref_name == 'latest') - uses: ansible-lockdown/github_linux_IaC/.github/workflows/export_badges_private.yml@self_hosted - with: - # Full org/repo path passed for GitHub API calls (e.g., ansible-lockdown/Private-Windows-2016-CIS) - repo_name: ${{ github.repository }} - secrets: - BADGE_PUSH_TOKEN: ${{ secrets.BADGE_PUSH_TOKEN }} diff --git a/.github/workflows/export_badges_public.yml b/.github/workflows/export_badges_public.yml deleted file mode 100644 index fa4b27f..0000000 --- a/.github/workflows/export_badges_public.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- - -name: Export Public Repo Badges - -on: - push: - branches: - - main - - devel - workflow_dispatch: - -jobs: - export-badges: - if: github.repository_visibility == 'public' && (github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && (github.ref_name == 'devel' || github.ref_name == 'main'))) - uses: ansible-lockdown/github_linux_IaC/.github/workflows/export_badges_public.yml@self_hosted - with: - repo_name: ${{ github.repository }} - secrets: - BADGE_PUSH_TOKEN: ${{ secrets.BADGE_PUSH_TOKEN }} diff --git a/.github/workflows/github_networks.tf b/.github/workflows/github_networks.tf new file mode 100644 index 0000000..ba77764 --- /dev/null +++ b/.github/workflows/github_networks.tf @@ -0,0 +1,53 @@ +resource "aws_vpc" "Main" { + cidr_block = var.main_vpc_cidr + instance_tenancy = "default" + tags = { + Environment = "${var.environment}" + Name = "${var.namespace}-VPC" + } +} + +resource "aws_internet_gateway" "IGW" { + vpc_id = aws_vpc.Main.id + tags = { + Environment = "${var.environment}" + Name = "${var.namespace}-IGW" + } +} + +resource "aws_subnet" "publicsubnets" { + vpc_id = aws_vpc.Main.id + cidr_block = var.public_subnets + availability_zone = var.availability_zone + tags = { + Environment = "${var.environment}" + Name = "${var.namespace}-pubsub" + } +} + +resource "aws_subnet" "Main" { + vpc_id = aws_vpc.Main.id + cidr_block = var.private_subnets + availability_zone = var.availability_zone + tags = { + Environment = "${var.environment}" + Name = "${var.namespace}-prvsub" + } +} + +resource "aws_route_table" "PublicRT" { + vpc_id = aws_vpc.Main.id + route { + cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.IGW.id + } + tags = { + Environment = "${var.environment}" + Name = "${var.namespace}-publicRT" + } +} + +resource "aws_route_table_association" "rt_associate_public" { + subnet_id = aws_subnet.Main.id + route_table_id = aws_route_table.PublicRT.id +} diff --git a/.github/workflows/github_vars.tfvars b/.github/workflows/github_vars.tfvars new file mode 100644 index 0000000..24daeca --- /dev/null +++ b/.github/workflows/github_vars.tfvars @@ -0,0 +1,14 @@ +// github_actions variables +// Resourced in github_networks.tf +// Declared in variables.tf +// + +namespace = "github_actions" +environment = "lockdown_github_repo_workflow" + +// Matching pair name found in AWS for keypairs PEM key +ami_key_pair_name = "github_actions" +private_key = ".ssh/github_actions.pem" +main_vpc_cidr = "172.22.0.0/24" +public_subnets = "172.22.0.128/26" +private_subnets = "172.22.0.192/26" diff --git a/.github/workflows/linux_benchmark_testing.yml b/.github/workflows/linux_benchmark_testing.yml new file mode 100644 index 0000000..8d26a35 --- /dev/null +++ b/.github/workflows/linux_benchmark_testing.yml @@ -0,0 +1,111 @@ +# This is a basic workflow to help you get started with Actions + +name: linux_benchmark_pipeline + +# Controls when the action will run. +# Triggers the workflow on push or pull request +# events but only for the devel branch +on: + pull_request_target: + types: [opened, reopened, synchronize] + branches: + - devel + - main + paths: + - '**.yml' + - '**.sh' + - '**.j2' + - '**.ps1' + - '**.cfg' + +# A workflow run is made up of one or more jobs +# that can run sequentially or in parallel +jobs: + # This will create messages for first time contributers and direct them to the Discord server + welcome: + runs-on: ubuntu-latest + + steps: + - uses: actions/first-interaction@main + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + pr-message: |- + Congrats on opening your first pull request and thank you for taking the time to help improve Ansible-Lockdown! + Please join in the conversation happening on the [Discord Server](https://discord.io/ansible-lockdown) as well. + # This workflow contains a single job called "build" + build: + # The type of runner that the job will run on + runs-on: ubuntu-latest + + env: + ENABLE_DEBUG: false + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, + # so your job can access it + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - name: Add_ssh_key + working-directory: .github/workflows + env: + SSH_AUTH_SOCK: /tmp/ssh_agent.sock + PRIVATE_KEY: "${{ secrets.SSH_PRV_KEY }}" + run: | + mkdir .ssh + chmod 700 .ssh + echo $PRIVATE_KEY > .ssh/github_actions.pem + chmod 600 .ssh/github_actions.pem + +### Build out the server + - name: Terraform_Init + working-directory: .github/workflows + run: terraform init + + - name: Terraform_Validate + working-directory: .github/workflows + run: terraform validate + + - name: Terraform_Apply + working-directory: .github/workflows + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: terraform apply -var-file "github_vars.tfvars" -var-file "OS.tfvars" --auto-approve -input=false + +## Debug Section + - name: DEBUG - Show Ansible hostfile + if: env.ENABLE_DEBUG == 'true' + working-directory: .github/workflows + run: cat hosts.yml + +# Aws deployments taking a while to come up insert sleep or playbook fails + + - name: Sleep for 60 seconds + run: sleep 60s + shell: bash + +# Run the ansible playbook + - name: Run_Ansible_Playbook + uses: arillso/action.playbook@master + with: + playbook: site.yml + inventory: .github/workflows/hosts.yml + galaxy_file: collections/requirements.yml + private_key: ${{ secrets.SSH_PRV_KEY }} +# verbose: 3 + env: + ANSIBLE_HOST_KEY_CHECKING: "false" + ANSIBLE_DEPRECATION_WARNINGS: "false" + +# Remove test system - User secrets to keep if necessary + + - name: Terraform_Destroy + working-directory: .github/workflows + if: always() && env.ENABLE_DEBUG == 'false' + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: terraform destroy -var-file "github_vars.tfvars" -var-file "OS.tfvars" --auto-approve -input=false diff --git a/.github/workflows/main.tf b/.github/workflows/main.tf new file mode 100644 index 0000000..516d5cc --- /dev/null +++ b/.github/workflows/main.tf @@ -0,0 +1,84 @@ +provider "aws" { + profile = "" + region = var.aws_region +} + +// Create a security group with access to port 22 and port 80 open to serve HTTP traffic + + +resource "random_id" "server" { + keepers = { + # Generate a new id each time we switch to a new AMI id + ami_id = "${var.ami_id}" + } + + byte_length = 8 +} + +resource "aws_security_group" "github_actions" { + name = "${var.namespace}-${random_id.server.hex}-SG" + vpc_id = aws_vpc.Main.id + + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + ingress { + from_port = 80 + to_port = 80 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + tags = { + Environment = "${var.environment}" + Name = "${var.namespace}-SG" + } +} + +// instance setup + +resource "aws_instance" "testing_vm" { + ami = var.ami_id + availability_zone = var.availability_zone + associate_public_ip_address = true + key_name = var.ami_key_pair_name # This is the key as known in the ec2 key_pairs + instance_type = var.instance_type + tags = var.instance_tags + vpc_security_group_ids = [aws_security_group.github_actions.id] + subnet_id = aws_subnet.Main.id + root_block_device { + delete_on_termination = true + } +} + +// generate inventory file +resource "local_file" "inventory" { + filename = "./hosts.yml" + directory_permission = "0755" + file_permission = "0644" + content = <> $GITHUB_ENV - echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}" - else - echo IAC_BRANCH=main >> $GITHUB_ENV - fi - - # Pull in terraform code for linux servers - - name: Clone GitHub IaC plan - uses: actions/checkout@v4 - with: - repository: ansible-lockdown/github_linux_IaC - path: .github/workflows/github_linux_IaC - ref: ${{ env.IAC_BRANCH }} - - # Uses dedicated restricted role and policy to enable this only for this task - # No credentials are part of github for AWS auth - - name: configure aws credentials - uses: aws-actions/configure-aws-credentials@main - with: - role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }} - role-session-name: ${{ secrets.AWS_ROLE_SESSION }} - aws-region: ${{ env.AWS_REGION }} - - - name: DEBUG - Show IaC files - if: env.ENABLE_DEBUG == 'true' - run: | - echo "OSVAR = $OSVAR" - echo "benchmark_type = $benchmark_type" - pwd - ls - env: - # Imported from GitHub variables this is used to load the relevant OS.tfvars file - OSVAR: ${{ vars.OSVAR }} - benchmark_type: ${{ vars.BENCHMARK_TYPE }} - - - name: Tofu init - id: init - run: tofu init - env: - # Imported from GitHub variables this is used to load the relevant OS.tfvars file - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - - - name: Tofu validate - id: validate - run: tofu validate - env: - # Imported from GitHub variables this is used to load the relevant OS.tfvars file - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - - - name: Tofu apply - id: apply - env: - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} - TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} - run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false - -## Debug Section - - name: DEBUG - Show Ansible hostfile - if: env.ENABLE_DEBUG == 'true' - run: cat hosts.yml - - # Aws deployments taking a while to come up insert sleep or playbook fails - - - name: Sleep to allow system to come up - run: sleep ${{ vars.BUILD_SLEEPTIME }} - - # Run the Ansible playbook - - name: Run_Ansible_Playbook - env: - ANSIBLE_HOST_KEY_CHECKING: "false" - ANSIBLE_DEPRECATION_WARNINGS: "false" - run: | - /opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml - - # Remove test system - User secrets to keep if necessary - - - name: Tofu Destroy - if: always() && env.ENABLE_DEBUG == 'false' - env: - OSVAR: ${{ vars.OSVAR }} - TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} - TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} - TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} - run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false diff --git a/.github/workflows/terraform.tfvars b/.github/workflows/terraform.tfvars new file mode 100644 index 0000000..d894ec4 --- /dev/null +++ b/.github/workflows/terraform.tfvars @@ -0,0 +1,6 @@ +// vars should be loaded by OSname.tfvars +availability_zone = "us-east-1b" +aws_region = "us-east-1" +ami_os = var.ami_os +ami_username = var.ami_username +instance_tags = var.instance_tags diff --git a/.github/workflows/variables.tf b/.github/workflows/variables.tf new file mode 100644 index 0000000..7e05228 --- /dev/null +++ b/.github/workflows/variables.tf @@ -0,0 +1,81 @@ +// Taken from the OSname.tfvars + +variable "aws_region" { + description = "AWS region" + default = "us-east-1" + type = string +} + +variable "availability_zone" { + description = "List of availability zone in the region" + default = "us-east-1b" + type = string +} + +variable "instance_type" { + description = "EC2 Instance Type" + default = "t3.micro" + type = string +} + +variable "instance_tags" { + description = "Tags to set for instances" + type = map(string) +} + +variable "ami_key_pair_name" { + description = "Name of key pair in AWS thats used" + type = string +} + +variable "private_key" { + description = "path to private key for ssh" + type = string +} + +variable "ami_os" { + description = "AMI OS Type" + type = string +} + +variable "ami_id" { + description = "AMI ID reference" + type = string +} + +variable "ami_username" { + description = "Username for the ami id" + type = string +} + +variable "ami_user_home" { + description = "home dir for the username" + type = string +} + +variable "namespace" { + description = "Name used across all tags" + type = string +} + +variable "environment" { + description = "Env Name used across all tags" + type = string +} + +// taken from github_vars.tfvars & + +variable "main_vpc_cidr" { + description = "Private cidr block to be used for vpc" + type = string +} + +variable "public_subnets" { + description = "public subnet cidr block" + type = string +} + +variable "private_subnets" { + description = "private subnet cidr block" + type = string +} diff --git a/.gitignore b/.gitignore index de8046f..8dd29c6 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,7 @@ delete* ignore* test_inv # temp remove doc while this is built up -doc/ +doc/ # VSCode .vscode @@ -46,6 +46,3 @@ benchparse/ # GitHub Action/Workflow files .github/ - -# Precommit exclusions -.ansible/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index dbc1d7e..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,71 +0,0 @@ ---- -##### CI for use by github no need for action to be added -##### Inherited -ci: - autofix_prs: false - skip: [detect-aws-credentials, ansible-lint ] - -repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v6.0.0 - hooks: - # Safety - - id: detect-aws-credentials - name: Detect AWS Credentials - - id: detect-private-key - name: Detect Private Keys - - # git checks - - id: check-merge-conflict - name: Check for merge conflicts - - id: check-added-large-files - name: Check for Large files - - id: check-case-conflict - name: Check case conflict - - # General checks - - id: trailing-whitespace - name: Trim Trailing Whitespace - description: This hook trims trailing whitespace. - entry: trailing-whitespace-fixer - language: python - types: [text] - args: [--markdown-linebreak-ext=md] - - id: end-of-file-fixer - name: Ensure line at end of file - -# Scan for passwords -- repo: https://github.com/Yelp/detect-secrets - rev: v1.5.0 - hooks: - - id: detect-secrets - -- repo: https://github.com/gitleaks/gitleaks - rev: v8.30.0 - hooks: - - id: gitleaks - -- repo: https://github.com/ansible-community/ansible-lint - rev: v25.12.2 - hooks: - - id: ansible-lint - name: Ansible-lint - description: This hook runs ansible-lint. - entry: python3 -m ansiblelint --force-color site.yml -c .ansible-lint - language: python - # do not pass files to ansible-lint, see: - # https://github.com/ansible/ansible-lint/issues/611 - pass_filenames: false - always_run: true - # additional_dependencies: - # https://github.com/pre-commit/pre-commit/issues/1526 - # If you want to use specific version of ansible-core or ansible, feel - # free to override `additional_dependencies` in your own hook config - # file. - # - ansible-core>=2.10.1 - -- repo: https://github.com/adrienverge/yamllint.git - rev: v1.37.1 # or higher tag - hooks: - - id: yamllint - name: Check YAML Lint diff --git a/.yamllint b/.yamllint index fa7b697..ec46929 100644 --- a/.yamllint +++ b/.yamllint @@ -1,38 +1,33 @@ --- extends: default + ignore: | tests/ molecule/ .github/ .gitlab-ci.yml *molecule.yml + rules: - braces: - max-spaces-inside: 1 - level: error - brackets: - max-spaces-inside: 1 - level: error - comments: - ignore-shebangs: true - min-spaces-from-content: 1 # prettier compatibility - comments-indentation: enable - empty-lines: - max: 1 - indentation: - # Requiring 2 space indentation - spaces: 2 - # Requiring consistent indentation within a file, either indented or not - indent-sequences: consistent - key-duplicates: enable - line-length: disable - new-line-at-end-of-file: enable - new-lines: - type: unix - octal-values: - forbid-implicit-octal: true # yamllint defaults to false - forbid-explicit-octal: true - trailing-spaces: enable - truthy: - allowed-values: ['true', 'false'] - check-keys: true + indentation: + # Requiring 4 space indentation + spaces: 4 + # Requiring consistent indentation within a file, either indented or not + indent-sequences: consistent + braces: + max-spaces-inside: 1 + level: error + brackets: + max-spaces-inside: 1 + level: error + empty-lines: + max: 1 + line-length: disable + key-duplicates: enable + new-line-at-end-of-file: enable + new-lines: + type: unix + trailing-spaces: enable + truthy: + allowed-values: ['true', 'false'] + check-keys: false diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 13e0b49..23ce2fb 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -61,6 +61,7 @@ following text in your contribution commit message: :: + This message can be entered manually, or if you have configured git with the correct `user.name` and `user.email`, you can use the `-s` option to `git commit` to automatically include the signoff message. diff --git a/Changelog.md b/Changelog.md index ac9c3b6..6fb56c4 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,157 +1,5 @@ # Changes to rhel9CIS -## 2.0.4 - Based on CIS v2.0.0 - -- addressed issue #393 thank you to @fragglexarmy -- addressed issue #394 thank you to @dbeuker -- addressed issues #390 and #391 thanks to @polski-g -- addressed issue #398 & #399 thanks to trumbaut -- Added max-concurrent options for audit -- work flow updates -- audit logic improvements -- auditd template 2.19 compatible -- pre-commit updates -- #410 thanks to @kpi-nourman -- #413 thanks to @bbaassssiiee - -## 2.0.3 - Based on CIS v2.0.0 -- addressed issue #387, thank you @fragglexarmy -- addressed issue #382 to improve regex logic on 5.4.2.4 -- improvement on crypto policy managed controls with var logic -- addressed issue #384 thank you @polski-g -- update command to shell module on tasks -- addressed issue 371 thanks to @bgro and kodebach -- addressed issue 350 thanks to @chrispipo -- addressed issue 364 thanks to @polski-g -- pre-commit update - -## 2.0.2 - Based on CIS v2.0.0 - -- Update to audit_only to allow fetching results -- resolved false warning for fetch audit -- fix root user check -- Improved documentation and variable compilation for crypto policies -- Addresses #318 - Thank you @kodebach & @bgro - - Improved logic for 5.2.4 to exclude rhel9cis_sudoers_exclude_nopasswd_list in pre-check tasks/main.yml - -## 2.0.1 - Based on CIS v2.0.0 - -- Thanks to @polski-g several issues and improvements added -- Improved testing for 50-redhat.conf for ssh -- 5.1.x regexp improvements -- Improved root password check -- egrep command changed to grep -E - -## 2.0.0 - Based on CIS v2.0.0 - -- #322, #325 - thanks to @mindrb -- #320 - thanks to @anup-ad - -## 1.1.6 - Based on CIS v1.0.0 - -- #190 - thanks to @ipruteanu-sie - - addressed requirements in PR with alternate method -- #191 - thanks to @numericillustration - - Addressed authselect for pam -- #193 thanks to brakkio86 - -## 1.1.5 - Based on CIS v1.0.0 - -- added new interactive user discoveries - - updated controls 6.2.10-6.2.14 -- audit - - steps moved to prelim - - update to coipy and archive logic and variables -- removed vars not used -- updated quotes used in mode tasks -- pre-commit update -- issues addressed - - #190 thanks to @ipruteanu-sie - - aligned logic for user shadow suite params (aligned with other repos) - - new variables to force changes to existing users added 5.6.1.1 - 5.6.1.2 - - #198 thanks to @brakkio86 - -## 1.1.4 - Based on CIS v1.0.0 - -- 1.2.1 new option for a new system to import gpg key for 1.2.1 to pass redhat only -- thanks to @ipruteanu-sie - - #156 - - #165 - - #180 - - #181 - - #183 - - #184 - -## 1.1.3 - Based on CIS v1.0.0 - -- updated goss binary to 0.4.4 -- moved majority of audit variables to vars/audit.yml -- new function to enable audit_only using remediation -- removed some dupes in audit config - -## 1.1.2 - Based on CIS v1.0.0 - -- updated audit binary versions - aligned with rhel9-cis-audit -- lint updates -- .secrets updated -- file mode quoted -- updated 5.6.5 thansk to feedback from S!ghs on discord community - -## 1.1.1 - Based on CIS v1.0.0 - -- thanks to @agbrowne - - [#90](https://github.com/ansible-lockdown/RHEL9-CIS/issues/90) - -- thanks to @mnasiadka - - [#54](https://github.com/ansible-lockdown/RHEL9-CIS/pull/54) - -## 1.1.0 - -- new workflow configuration - - Allowing devel and main configs - - IaC code found in alternate repo for easier mgmt -- Added pre-commit config - Does not have to be used but can improve things - - .pre-commit-config.yaml - - .secrets.baseline - - gitleaks and secrets detection - -- updated to logic in 5.6.5 -- lint updates to 6.1.x -- readme updates -- audit control updates and variable name changes - - ability to run audit on arm64(e.g. pi or M1/2) too thanks to @lucab85 #77 -- tidy up README adopted PR #78 thanks to @lucab85 -- moved Makefile requirements to .config/ -- removed .ansible.cfg and local.yml - -## 1.0.10 - -- [#72](https://github.com/ansible-lockdown/RHEL9-CIS/issues/72) - - Only run check when paybook user not a superuser -- fix for 5.5.3 thanks to @nrg-fv - -## 1.0.9 - -fixed assert for user password set - -thanks to @byjunks -[#66](https://github.com/ansible-lockdown/RHEL9-CIS/issues/66) - -## 1.0.8 - -rule_1.10 improvements allowing for module checking (useful for AD) - -## 1.0.7 - -lint and yaml updates -improvements to 6.1.10, 6.1.11, 6.1.13, 6.1.14 -4.1.3.6 updated on process discovery - -## 1.0.6 - -updated yamllint as galaxy doesn't honour local settings -removed empty lines in files - ## 1.0.5 updated yamllint @@ -186,8 +34,8 @@ Aligned benchmark audit version with remediate release ## 1.0.1 -Control 6_2_16 new variable added thanks to @dulin_gnet on rhel8 -Will not follow symlink in home directories and amend permissions. +Control 6_2_16 new variable added thanks to @dulin_gnet on rhel8 +Will not follow ynlink in hoe directoris and amend permissions. - rhel_09_6_2_16_home_follow_symlink: false diff --git a/LICENSE b/LICENSE index 7e51eb7..4f5e4fd 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Mindpoint Group - A Tyto Athene Company / Ansible Lockdown +Copyright (c) 2022 Mindpoint Group / Lockdown Enterprise / Lockdown Enterprise Releases Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index 99029ac..5d7a9b3 100755 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ .PHONY: all help galaxy-install ansible-list yamllint pip-requirements + GALAXY=ansible-galaxy ANSIBLE_LINT='/usr/local/bin/ansible-lint' ANSIBLE_FILE=site.yml @@ -14,6 +15,7 @@ help: @echo " yamllint to lint playbook files" @echo " pip-requirements add pip required file" + galaxy-install: $(GALAXY) install -r ./collections/requirements.yml @@ -25,5 +27,6 @@ yamllint: pip-requirements: @echo 'Python dependencies:' - @cat .config/requirements.txt + @cat requirements.txt pip3 install -r requirements.txt + diff --git a/README.md b/README.md index 65a8fca..71e7636 100644 --- a/README.md +++ b/README.md @@ -1,205 +1,89 @@ + # RHEL 9 CIS -## Configure a RHEL 9 machine to be [CIS](https://www.cisecurity.org/cis-benchmarks/) compliant +## v1.0.0 - released Dec 2022 -### Based on [CIS RedHat Enterprise Linux 9 Benchmark v2.0.0](https://www.cisecurity.org/cis-benchmarks/) +![Build Status](https://img.shields.io/github/workflow/status/ansible-lockdown/RHEL9-CIS/CommunityToDevel?label=Devel%20Build%20Status&style=plastic) +![Build Status](https://img.shields.io/github/workflow/status/ansible-lockdown/RHEL9-CIS/DevelToMain?label=Main%20Build%20Status&style=plastic) +![Release](https://img.shields.io/github/v/release/ansible-lockdown/RHEL9-CIS?style=plastic) ---- +Configure RHEL 9 machine to be [CIS](https://www.cisecurity.org/cis-benchmarks/) -## Public Repository 📣 +Based on [CIS RedHat Enterprise Linux 9 Benchmark v1.0.0. - 11-30-2022 ](https://www.cisecurity.org/cis-benchmarks/) -![Org Stars](https://img.shields.io/github/stars/ansible-lockdown?label=Org%20Stars&style=social) -![Stars](https://img.shields.io/github/stars/ansible-lockdown/RHEL9-CIS?label=Repo%20Stars&style=social) -![Forks](https://img.shields.io/github/forks/ansible-lockdown/RHEL9-CIS?style=social) -![Followers](https://img.shields.io/github/followers/ansible-lockdown?style=social) -[![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/AnsibleLockdown.svg?style=social&label=Follow%20%40AnsibleLockdown)](https://twitter.com/AnsibleLockdown) -![Discord Badge](https://img.shields.io/discord/925818806838919229?logo=discord) +## Join us -![License](https://img.shields.io/github/license/ansible-lockdown/RHEL9-CIS?label=License) +On our [Discord Server](https://discord.io/ansible-lockdown) to ask questions, discuss features, or just chat with other Ansible-Lockdown users -## Lint & Pre-Commit Tools 🔧 +## Caution(s) -[![Pre-Commit.ci](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/RHEL9-CIS/pre-commit-ci.json)](https://results.pre-commit.ci/latest/github/ansible-lockdown/RHEL9-CIS/devel) -![YamlLint](https://img.shields.io/badge/yamllint-Present-brightgreen?style=flat&logo=yaml&logoColor=white) -![Ansible-Lint](https://img.shields.io/badge/ansible--lint-Present-brightgreen?style=flat&logo=ansible&logoColor=white) +This role **will make changes to the system** which may have unintended concequences. -## Community Release Information 📂 +This role was developed against a clean install of the Operating System. If you are implimenting to an existing system please review this role for any site specific changes that are needed. -![Release Branch](https://img.shields.io/badge/Release%20Branch-Main-brightgreen) -![Release Tag](https://img.shields.io/github/v/tag/ansible-lockdown/RHEL9-CIS?label=Release%20Tag&&color=success) -![Main Release Date](https://img.shields.io/github/release-date/ansible-lockdown/RHEL9-CIS?label=Release%20Date) -![Benchmark Version Main](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/RHEL9-CIS/benchmark-version-main.json) -![Benchmark Version Devel](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/RHEL9-CIS/benchmark-version-devel.json) +To use release version please point to main branch -[![Main Pipeline Status](https://github.com/ansible-lockdown/RHEL9-CIS/actions/workflows/main_pipeline_validation.yml/badge.svg?)](https://github.com/ansible-lockdown/RHEL9-CIS/actions/workflows/main_pipeline_validation.yml) +## Documentation -[![Devel Pipeline Status](https://github.com/ansible-lockdown/RHEL9-CIS/actions/workflows/devel_pipeline_validation.yml/badge.svg?)](https://github.com/ansible-lockdown/RHEL9-CIS/actions/workflows/devel_pipeline_validation.yml) +- [Readthedocs](https://ansible-lockdown.readthedocs.io/en/latest/) +- [Getting Started](https://www.lockdownenterprise.com/docs/getting-started-with-lockdown) +- [Customizing Roles](https://www.lockdownenterprise.com/docs/customizing-lockdown-enterprise) +- [Per-Host Configuration](https://www.lockdownenterprise.com/docs/per-host-lockdown-enterprise-configuration) +- [Getting the Most Out of the Role](https://www.lockdownenterprise.com/docs/get-the-most-out-of-lockdown-enterprise) +## Requirements -![Devel Commits](https://img.shields.io/github/commit-activity/m/ansible-lockdown/RHEL9-CIS/devel?color=dark%20green&label=Devel%20Branch%20Commits) -![Open Issues](https://img.shields.io/github/issues-raw/ansible-lockdown/RHEL9-CIS?label=Open%20Issues) -![Closed Issues](https://img.shields.io/github/issues-closed-raw/ansible-lockdown/RHEL9-CIS?label=Closed%20Issues&&color=success) -![Pull Requests](https://img.shields.io/github/issues-pr/ansible-lockdown/RHEL9-CIS?label=Pull%20Requests) +RHEL 9 +Almalinux 9 +Rocky 9 +OracleLinux 9 ---- +ansible 2.10 +jmespath +relevant collections -## Subscriber Release Information 🔐 +- Access to download or add the goss binary and content to the system if using auditing (other options are available on how to get the content to the system.) -![Private Release Branch](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/Private-RHEL9-CIS/release-branch.json) -![Private Benchmark Version](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/Private-RHEL9-CIS/benchmark-version.json) +## Tested with -[![Private Remediate Pipeline](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/Private-RHEL9-CIS/remediate.json)](https://github.com/ansible-lockdown/Private-RHEL9-CIS/actions/workflows/main_pipeline_validation.yml) -[![Private GPO Pipeline](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/Private-RHEL9-CIS/gpo.json)](https://github.com/ansible-lockdown/Private-RHEL9-CIS/actions/workflows/main_pipeline_validation_gpo.yml) +ansible-base 2.10.17 - python 3.8 +ansible-core 2.13.4 - python 3.10 -![Private Pull Requests](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/Private-RHEL9-CIS/prs.json) -![Private Closed Issues](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/Private-RHEL9-CIS/issues-closed.json) +- makefile - this is there purely for testing and initial setup purposes. ---- - -## Looking for support? 🤝 - -[Lockdown Enterprise](https://www.lockdownenterprise.com#GH_AL_RHEL9-CIS) - -[Ansible support](https://www.mindpointgroup.com/cybersecurity-products/ansible-counselor#GH_AL_RHEL9-CIS) - -### Community 💬 - -On our [Discord Server](https://www.lockdownenterprise.com/discord) to ask questions, discuss features, or just chat with other Ansible-Lockdown users - ---- - -## 🚨 Caution(s) 🚨 - -This role **will make changes to the system** which may have unintended consequences. This is not an auditing tool but rather a remediation tool to be used after an audit has been conducted. - -- Testing is the most important thing you can do. - -- Check Mode is not guaranteed! 🚫 The role will complete in check mode without errors, but it is not supported and should be used with caution. - -- This role was developed against a clean install of the Operating System. If you are implementing to an existing system please review this role for any site specific changes that are needed. - -- To use release version please point to main branch and relevant release for the cis benchmark you wish to work with. - -- Did we mention testing?? - ---- - -## Coming From A Previous Release ⏪ - -CIS release always contains changes, it is highly recommended to review the new references and available variables. This have changed significantly since ansible-lockdown initial release. -This is now compatible with python3 if it is found to be the default interpreter. This does come with pre-requisites which it configures the system accordingly. - -Further details can be seen in the [Changelog](./ChangeLog.md) - ---- - -## Matching a security Level for CIS - -It is possible to only run level 1 or level 2 controls for CIS. -This is managed using tags: - -- level1-server -- level1-workstation -- level2-server -- level2-workstation - -The control found in defaults main also need to reflect this as this control the testing that takes place if you are using the audit component. - ---- -## Requirements ✅ - -**General:** +## General - Basic knowledge of Ansible, below are some links to the Ansible documentation to help get started if you are unfamiliar with Ansible - - [Main Ansible documentation page](https://docs.ansible.com) - [Ansible Getting Started](https://docs.ansible.com/ansible/latest/user_guide/intro_getting_started.html) - [Tower User Guide](https://docs.ansible.com/ansible-tower/latest/html/userguide/index.html) - [Ansible Community Info](https://docs.ansible.com/ansible/latest/community/index.html) + - Functioning Ansible and/or Tower Installed, configured, and running. This includes all of the base Ansible/Tower configurations, needed packages installed, and infrastructure setup. -- Please read through the tasks in this role to gain an understanding of what each control is doing. Some of the tasks are disruptive and can have unintended consequences in a live production system. Also familiarize yourself with the variables in the defaults/main.yml file. +- Please read through the tasks in this role to gain an understanding of what each control is doing. + - Some of the tasks are disruptive and can have unintended consiquences in a live production system. Also familiarize yourself with the variables in the defaults/main.yml file -**Technical Dependencies:** +## Dependencies -RHEL Family OS 9 - -- Access to download or add the goss binary and content to the system if using auditing -(other options are available on how to get the content to the system.) -- Python3.8 -- Ansible 2.12+ -- python-def +- Python3 +- Ansible 2.9+ +- python-def (should be included in RHEL 9) - libselinux-python - ---- - -## Auditing 🔍 - -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. - -This is a much quicker, very lightweight, checking (where possible) config compliance and live/running settings. - -A new 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. -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. - -Refer to [RHEL9-CIS-Audit](https://github.com/ansible-lockdown/RHEL9-CIS-Audit). - -## Example Audit Summary - -This is based on a vagrant image with selections enabled. e.g. No Gui or firewall. -Note: More tests are run during audit as we check config and running state. - -```txt - -ok: [default] => { - "msg": [ - "The pre remediation results are: ['Total Duration: 5.454s', 'Count: 338, Failed: 47, Skipped: 5'].", - "The post remediation results are: ['Total Duration: 5.007s', 'Count: 338, Failed: 46, Skipped: 5'].", - "Full breakdown can be found in /var/tmp", - "" - ] -} - -PLAY RECAP ******************************************************************************************************************************************* -default : ok=270 changed=23 unreachable=0 failed=0 skipped=140 rescued=0 ignored=0 -``` - -## Documentation 📖 - -- [Read The Docs](https://ansible-lockdown.readthedocs.io/en/latest/) -- [Getting Started](https://www.lockdownenterprise.com/docs/getting-started-with-lockdown#GH_AL_RH9_cis) -- [Customizing Roles](https://www.lockdownenterprise.com/docs/customizing-lockdown-enterprise#GH_AL_RH9_cis) -- [Per-Host Configuration](https://www.lockdownenterprise.com/docs/per-host-lockdown-enterprise-configuration#GH_AL_RH9_cis) -- [Getting the Most Out of the Role](https://www.lockdownenterprise.com/docs/get-the-most-out-of-lockdown-enterprise#GH_AL_RH9_cis) - +- pip packages + - jmespath ( complete list found in requirements.txt) +- collections found in collections/requirememnts.yml ## Role Variables -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. +This role is designed that the end user should not have to edit the tasks themselves. All customizing should be done by overriding the required varaibles as found in defaults/main.yml file. e.g. using inventory, group_vars, extra_vars -## Tags 🏷️ +## Tags -There are many tags available for added control precision. Each control has its own set of tags noting what level, what OS element it relates to, whether it's a patch or audit, and the rule number. Additionally, NIST references follow a specific conversion format for consistency and clarity. +There are many tags available for added control precision. Each control has it's own set of tags noting what level, if it's scored/notscored, what OS element it relates to, if it's a patch or audit, and the rule number. -### Conversion Format for NIST References: - - 1. Standard Prefix: - - - All references are prefixed with "NIST". - - 2. Standard Types: - - - "800-53" references are formatted as NIST800-53. - - "800-53r5" references are formatted as NIST800-53R5 (with 'R' capitalized). - - "800-171" references are formatted as NIST800-171. - - 3. Details: - - - Section and subsection numbers use periods (.) for numeric separators. - - Parenthetical elements are separated by underscores (_), e.g., IA-5(1)(d) becomes IA-5_1_d. - - Subsection letters (e.g., "b") are appended with an underscore. 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 services, this task will be skipped. The opposite can also happen where you run only controls tagged with services. -```sh +```txt tags: - level1-server - level1-workstation @@ -210,55 +94,9 @@ Below is an example of the tag section from a control within this role. Using th - rule_2.2.4 ``` +### Known Issues -## Community Contribution 🧑‍🤝‍🧑 - -We encourage you (the community) to contribute to this role. Please read the rules below. - -- Your work is done in your own individual branch. Make sure to Signed-off-by and GPG sign all commits you intend to merge. -- All community Pull Requests are pulled into the devel branch -- Pull Requests into devel will confirm your commits have a GPG signature, Signed-off-by, and a functional test before being approved -- 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 - -## Pipeline Testing 🔄 - -uses: - -- ansible-core 2.16 -- ansible collections - pulls in the latest version based on requirements file -- runs the audit using the devel branch -- This is an automated test that occurs on pull requests into devel -- self-hosted runners using OpenTofu - -## Known Issues - -Almalinux BaseOS, EPEL and many cloud providers repositories, do not allow gpgcheck(rule_1.2.1.2) or repo_gpgcheck (rule_1.2.1.3) this will cause issues during the playbook unless or a workaround is found. - - -## Local Testing 💻 - -### example - -```bash -molecule test -s default -molecule converge -s wsl -- --check -molecule verify -s localhost -``` - -local testing uses: - -- ansible-core -- molecule 4.0.1 -- molecule-docker 2.0.0 -- molecule-podman 2.0.2 -- molecule-vagrant 1.0.0 -- molecule-azure 0.5.0 - - -## Credits and Thanks 🙏 - -Massive thanks to the fantastic community and all its members. - -This includes a huge thanks and credit to the original authors and maintainers. - -Mark Bolwell, George Nalen, Steve Williams, Fred Witty +CIS 1.2.4 - repo_gpgcheck is not carried out for RedHat hosts as the default repos do not have this function. This also affect EPEL(not covered by var). + - Rocky and Alma not affected. +Variable used to unset. +rhel9cis_rhel_default_repo: true # to be set to false if using repo that does have this ability diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..3bc6e07 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,31 @@ +[defaults] +host_key_checking=False +display_skipped_hosts=True +system_warnings=False +command_warnings=False +nocows=1 +retry_files_save_path=/dev/null +pipelining=true + +# Use the YAML callback plugin. +stdout_callback = yaml +# Use the stdout_callback when running ad-hoc commands. +bin_ansible_callbacks = True + + +[privilege_escalation] + +[paramiko_connection] +record_host_keys=False + +[ssh_connection] +transfer_method=scp +ssh_args = -o ControlMaster=auto -o ControlPersist=60s + +[accelerate] + +[selinux] + +[colors] + +[diff] diff --git a/collections/requirements.yml b/collections/requirements.yml index 810c9af..d35b7e9 100644 --- a/collections/requirements.yml +++ b/collections/requirements.yml @@ -1,14 +1,5 @@ --- - collections: - - name: community.general - source: https://github.com/ansible-collections/community.general - type: git - - - name: community.crypto - source: https://github.com/ansible-collections/community.crypto - type: git - - - name: ansible.posix - source: https://github.com/ansible-collections/ansible.posix - type: git +- name: community.general +- name: community.crypto +- name: ansible.posix diff --git a/defaults/main.yml b/defaults/main.yml index f620a72..7ea583d 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -1,251 +1,136 @@ --- # defaults file for rhel9-cis -# WARNING: -# These values may be overridden by other vars-setting options(e.g. like the below 'container_vars_file'), as explained here: -# https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable + +system_is_container: false +container_vars_file: is_container.yml +# rhel9cis is left off the front of this var for consistency in testing pipeline +# system_is_ec2 toggle will disable tasks that fail on Amazon EC2 instances. Set true to skip and false to run tasks +system_is_ec2: false # Run the OS validation check -# Supported OSs will not need for this to be changed - see README e.g. CentOS os_check: true -# Disruption is high -## Run tests that are considered higher risk and could have a system impact if not properly tested -## Default false -## Will be fine if clean new un-configured build -rhel9cis_disruption_high: true - -## Switching on/off specific baseline sections -# These variables govern whether the tasks of a particular section are to be executed when running the role. -# E.g: If you want to execute the tasks of Section 1 you should set the "_section1" variable to true. -# If you do not want the tasks from that section to get executed you simply set the variable to "false". -# Some sections support sub-section modularization. The super-section and sub-section must both be true -# for the sub-section to execute. rhel9cis_section1: true rhel9cis_section2: true rhel9cis_section3: true rhel9cis_section4: true rhel9cis_section5: true -rhel9cis_section5_1: true -rhel9cis_section5_2: true -rhel9cis_section5_3: true -rhel9cis_section5_4: true rhel9cis_section6: true -rhel9cis_section7: true -# This is used for audit purposes to run only specific level use the tags +# This is used for audit purposes to run only specifc level use the tags # e.g. # - level1-server # - level2-workstation rhel9cis_level_1: true rhel9cis_level_2: true -# Create managed not custom local_facts files -create_benchmark_facts: true -# The path where the ansible facts file is created if audit facts are not present -ansible_facts_path: /etc/ansible/facts.d - -## Section 1.6 - Mandatory Access Control -# This variable governs whether SELinux is disabled or not. If SELinux is NOT DISABLED by setting -# 'rhel9cis_selinux_disable' to 'true', the 1.6 subsection will be executed. rhel9cis_selinux_disable: false -# This variable is used in a preliminary task, handling grub2 paths either in case of -# UEFI boot('/etc/grub2-efi.cfg') or in case of BIOS legacy-boot('/etc/grub2.cfg'). rhel9cis_legacy_boot: false -## Benchmark name used by auditing control role +## Python Binary +## This is used for python3 Installations where python2 OS modules are used in ansible +python2_bin: /bin/python2.7 + +## Benchmark name used by audting control role # The audit variable found at the base ## metadata for Audit benchmark -benchmark_version: 'v2.0.0' +benchmark_version: 'v1.0.0' benchmark: RHEL9-CIS -# Whether to skip the system reboot before audit -# System will reboot if false, can give better audit results +# Whether to skip the reboot skip_reboot: true # default value will change to true but wont reboot if not enabled but will error change_requires_reboot: false -### -### Settings for associated Audit role using Goss -### +#### Basic external goss audit enablement settings #### +#### Precise details - per setting can be found at the bottom of this file #### -########################################### -### Goss is required on the remote host ### -### vars/auditd.yml for other settings ### - -## Audit setup -# Audits are carried out using Goss. This variable -# determines whether execution of the role prepares for auditing -# by installing the required binary. +### Goss is required on the remote host setup_audit: false +# How to retrive goss +# Options are copy or download - detailed settings at the bottom of this file +# you will need to access to either github or the file already dowmloaded +get_goss_file: download -## Enable audits to run - this runs the audit and get the latest content -# This variable governs whether the audit using the -# separately maintained audit role using Goss -# is carried out. -# This runs the audit and gets the latest content -run_audit: false -# Run heavy tests - some tests can have more impact on a system enabling these can have greater impact on a system -audit_run_heavy_tests: true -# Ability to limit the number of concurrent processes used by goss (default 50) -audit_max_concurrent: 50 - -## Only run Audit do not remediate -audit_only: false -### As part of audit_only ### -# Path to copy the files to will create dir structure in audit_only mode -audit_capture_files_dir: /some/location to copy to on control node -############################# - -## How to retrieve audit binary(Goss) -# Options are 'copy' or 'download' - detailed settings at the bottom of this file -# - if 'copy': -# - the filepath mentioned via the below 'audit_bin_copy_location' var will be used to access already downloaded Goss -# - if 'download': -# - the GitHub Goss-releases URL will be used for a fresh-download, via 'audit_bin_url' and 'audit_pkg_arch_name' vars -get_audit_binary_method: download - -## if get_audit_binary_method - copy the following needs to be updated for your environment -## it is expected that it will be copied from somewhere accessible to the control node -## e.g copy from ansible control node to remote host -audit_bin_copy_location: /some/accessible/path - -## How to retrieve the audit role -# The role for auditing is maintained separately. -# This variable specifies the method of how to get the audit role -# options are git/copy/archive/get_url other e.g. if you wish to run from already downloaded conf -# onto the system. The options are as follows: -# - 'git': clone audit content from GitHub REPOSITORY, set up via `audit_file_git` var, and -# VERSION(e.g. branch, tag name), set up via `audit_git_version` var. -# - 'copy': copy from path as specified in variable `audit_conf_copy`. -# - 'archive': same as 'copy', only that the specified filepath needs to be unpacked. -# - 'get_url': Download from url as specified in variable `audit_files_url` +# how to get audit files onto host options +# options are git/copy/get_url - use local if already available to to the host (adjust paths accordingly) audit_content: git -# If using either archive, copy, get_url: -## Note will work with .tar files - zip will require extra configuration -### If using get_url this is expecting github url in tar.gz format e.g. -### https://github.com/ansible-lockdown/RHEL9-CIS-Audit/archive/refs/heads/benchmark-v1.0.0.tar.gz -audit_conf_source: "some path or url to copy from" +# enable audits to run - this runs the audit and get the latest content +run_audit: false -# Destination for the audit content to be placed on managed node -# note may not need full path e.g. /opt with the directory being the {{ benchmark }}-Audit directory -audit_conf_dest: "/opt" +# Timeout for those cmds that take longer to run where timeout set +audit_cmd_timeout: 60000 -# Where the audit logs are stored -audit_log_dir: '/opt' - -## Ability to collect and take audit files moving to a centralized location -# This enables the collection of the files from the host -fetch_audit_output: false - -# Method of getting,uploading the summary files -## Ensure access and permissions are available for these to occur. -## options are -# fetch - fetches from server and moves to location on the ansible controller (could be a mount point available to controller) -# copy - copies file to a location available to the managed node -audit_output_collection_method: fetch - -# Location to put the audit files -audit_output_destination: /opt/audit_summaries/ - -### Goss Settings ## -####### END ######## +### End Goss enablements #### +#### Detailed settings found at the end of this document #### # These variables correspond with the CIS rule IDs or paragraph numbers defined in # the CIS benchmark documents. # PLEASE NOTE: These work in coordination with the section # group variables and tags. # You must enable an entire section in order for the variables below to take effect. - -## Section 1 Fixes -# Section 1 is Initial setup (FileSystem Configuration, Configure Software Updates, Filesystem Integrity Checking, Secure Boot Settings, -# Additional Process Hardening, Mandatory Access Control, Command Line Warning Banners, and GNOME Display Manager) -# Filesystem kernel modules +# Section 1 rules rhel9cis_rule_1_1_1_1: true rhel9cis_rule_1_1_1_2: true -rhel9cis_rule_1_1_1_3: true -rhel9cis_rule_1_1_1_4: true -rhel9cis_rule_1_1_1_5: true -rhel9cis_rule_1_1_1_6: true -rhel9cis_rule_1_1_1_7: true -rhel9cis_rule_1_1_1_8: true -rhel9cis_rule_1_1_1_9: true -# Filesystems -# /tmp -rhel9cis_rule_1_1_2_1_1: true -rhel9cis_rule_1_1_2_1_2: true -rhel9cis_rule_1_1_2_1_3: true -rhel9cis_rule_1_1_2_1_4: true -# /dev/shm -rhel9cis_rule_1_1_2_2_1: true -rhel9cis_rule_1_1_2_2_2: true -rhel9cis_rule_1_1_2_2_3: true -rhel9cis_rule_1_1_2_2_4: true -# /home -rhel9cis_rule_1_1_2_3_1: true -rhel9cis_rule_1_1_2_3_2: true -rhel9cis_rule_1_1_2_3_3: true -# /var -rhel9cis_rule_1_1_2_4_1: true -rhel9cis_rule_1_1_2_4_2: true -rhel9cis_rule_1_1_2_4_3: true -# /var/tmp -rhel9cis_rule_1_1_2_5_1: true -rhel9cis_rule_1_1_2_5_2: true -rhel9cis_rule_1_1_2_5_3: true -rhel9cis_rule_1_1_2_5_4: true -# /var/log -rhel9cis_rule_1_1_2_6_1: true -rhel9cis_rule_1_1_2_6_2: true -rhel9cis_rule_1_1_2_6_3: true -rhel9cis_rule_1_1_2_6_4: true -# /var/log/audit -rhel9cis_rule_1_1_2_7_1: true -rhel9cis_rule_1_1_2_7_2: true -rhel9cis_rule_1_1_2_7_3: true -rhel9cis_rule_1_1_2_7_4: true -# Package Mgmt -# Config Pkg Repos -rhel9cis_rule_1_2_1_1: true -rhel9cis_rule_1_2_1_2: true -rhel9cis_rule_1_2_1_3: true -rhel9cis_rule_1_2_1_4: true -# Package updates -rhel9cis_rule_1_2_2_1: true -# Selinux -rhel9cis_rule_1_3_1_1: true -rhel9cis_rule_1_3_1_2: true -rhel9cis_rule_1_3_1_3: true -rhel9cis_rule_1_3_1_4: true -rhel9cis_rule_1_3_1_5: true -rhel9cis_rule_1_3_1_6: true -rhel9cis_rule_1_3_1_7: true -rhel9cis_rule_1_3_1_8: true -# Bootloader +rhel9cis_rule_1_1_2_1: true +rhel9cis_rule_1_1_2_2: true +rhel9cis_rule_1_1_2_3: true +rhel9cis_rule_1_1_2_4: true +rhel9cis_rule_1_1_3_1: true +rhel9cis_rule_1_1_3_2: true +rhel9cis_rule_1_1_3_3: true +rhel9cis_rule_1_1_4_1: true +rhel9cis_rule_1_1_4_2: true +rhel9cis_rule_1_1_4_3: true +rhel9cis_rule_1_1_4_4: true +rhel9cis_rule_1_1_5_1: true +rhel9cis_rule_1_1_5_2: true +rhel9cis_rule_1_1_5_3: true +rhel9cis_rule_1_1_5_4: true +rhel9cis_rule_1_1_6_1: true +rhel9cis_rule_1_1_6_2: true +rhel9cis_rule_1_1_6_3: true +rhel9cis_rule_1_1_6_4: true +rhel9cis_rule_1_1_7_1: true +rhel9cis_rule_1_1_7_2: true +rhel9cis_rule_1_1_7_3: true +rhel9cis_rule_1_1_8_1: true +rhel9cis_rule_1_1_8_2: true +rhel9cis_rule_1_1_8_3: true +rhel9cis_rule_1_1_8_4: true +rhel9cis_rule_1_1_18: true +rhel9cis_rule_1_1_19: true +rhel9cis_rule_1_1_20: true +rhel9cis_rule_1_1_21: true +rhel9cis_rule_1_1_9: true +rhel9cis_rule_1_2_1: true +rhel9cis_rule_1_2_2: true +rhel9cis_rule_1_2_3: true +rhel9cis_rule_1_2_4: true +rhel9cis_rule_1_3_1: true +rhel9cis_rule_1_3_2: true +rhel9cis_rule_1_3_3: true rhel9cis_rule_1_4_1: true rhel9cis_rule_1_4_2: true -# Additional Process Hardening rhel9cis_rule_1_5_1: true rhel9cis_rule_1_5_2: true rhel9cis_rule_1_5_3: true -rhel9cis_rule_1_5_4: true -# Config system wide Crypto -rhel9cis_rule_1_6_1: true -rhel9cis_rule_1_6_2: true -rhel9cis_rule_1_6_3: true -rhel9cis_rule_1_6_4: true -rhel9cis_rule_1_6_5: true -rhel9cis_rule_1_6_6: true -rhel9cis_rule_1_6_7: true -# Command line warning banners +rhel9cis_rule_1_6_1_1: true +rhel9cis_rule_1_6_1_2: true +rhel9cis_rule_1_6_1_3: true +rhel9cis_rule_1_6_1_4: true +rhel9cis_rule_1_6_1_5: true +rhel9cis_rule_1_6_1_6: true +rhel9cis_rule_1_6_1_7: true +rhel9cis_rule_1_6_1_8: true rhel9cis_rule_1_7_1: true rhel9cis_rule_1_7_2: true rhel9cis_rule_1_7_3: true rhel9cis_rule_1_7_4: true rhel9cis_rule_1_7_5: true rhel9cis_rule_1_7_6: true -# Gnome Display Manager rhel9cis_rule_1_8_1: true rhel9cis_rule_1_8_2: true rhel9cis_rule_1_8_3: true @@ -256,67 +141,42 @@ rhel9cis_rule_1_8_7: true rhel9cis_rule_1_8_8: true rhel9cis_rule_1_8_9: true rhel9cis_rule_1_8_10: true +rhel9cis_rule_1_9: true +rhel9cis_rule_1_10: true -## Section 2 Fixes -# Section 2 rules are controlling Services (Special Purpose Services, and service clients) -# Configure Server Services +# Section 2 rules rhel9cis_rule_2_1_1: true rhel9cis_rule_2_1_2: true -rhel9cis_rule_2_1_3: true -rhel9cis_rule_2_1_4: true -rhel9cis_rule_2_1_5: true -rhel9cis_rule_2_1_6: true -rhel9cis_rule_2_1_7: true -rhel9cis_rule_2_1_8: true -rhel9cis_rule_2_1_9: true -rhel9cis_rule_2_1_10: true -rhel9cis_rule_2_1_11: true -rhel9cis_rule_2_1_12: true -rhel9cis_rule_2_1_13: true -rhel9cis_rule_2_1_14: true -rhel9cis_rule_2_1_15: true -rhel9cis_rule_2_1_16: true -rhel9cis_rule_2_1_17: true -rhel9cis_rule_2_1_18: true -rhel9cis_rule_2_1_19: true -rhel9cis_rule_2_1_20: true -rhel9cis_rule_2_1_21: true -rhel9cis_rule_2_1_22: true -# Configure Client Services rhel9cis_rule_2_2_1: true rhel9cis_rule_2_2_2: true rhel9cis_rule_2_2_3: true rhel9cis_rule_2_2_4: true rhel9cis_rule_2_2_5: true -# Configure Time Synchronization +rhel9cis_rule_2_2_6: true +rhel9cis_rule_2_2_7: true +rhel9cis_rule_2_2_8: true +rhel9cis_rule_2_2_9: true +rhel9cis_rule_2_2_10: true +rhel9cis_rule_2_2_11: true +rhel9cis_rule_2_2_12: true +rhel9cis_rule_2_2_13: true +rhel9cis_rule_2_2_14: true +rhel9cis_rule_2_2_15: true +rhel9cis_rule_2_2_16: true +rhel9cis_rule_2_2_17: true +rhel9cis_rule_2_2_18: true rhel9cis_rule_2_3_1: true rhel9cis_rule_2_3_2: true rhel9cis_rule_2_3_3: true -# Job Schedulers -# cron -rhel9cis_rule_2_4_1_1: true -rhel9cis_rule_2_4_1_2: true -rhel9cis_rule_2_4_1_3: true -rhel9cis_rule_2_4_1_4: true -rhel9cis_rule_2_4_1_5: true -rhel9cis_rule_2_4_1_6: true -rhel9cis_rule_2_4_1_7: true -rhel9cis_rule_2_4_1_8: true -# at -rhel9cis_rule_2_4_2_1: true +rhel9cis_rule_2_3_4: true +rhel9cis_rule_2_4: true -## Section 3 Fixes -# Section 3 rules are used for securely configuring the network configuration(kernel params, ACL, Firewall settings) -# Network Devices +# Section 3 rules rhel9cis_rule_3_1_1: true rhel9cis_rule_3_1_2: true rhel9cis_rule_3_1_3: true -# Network Kernel Modules rhel9cis_rule_3_2_1: true rhel9cis_rule_3_2_2: true -rhel9cis_rule_3_2_3: true -rhel9cis_rule_3_2_4: true -# Network Kernel Parameters rhel9cis_rule_3_3_1: true rhel9cis_rule_3_3_2: true rhel9cis_rule_3_3_3: true @@ -326,28 +186,76 @@ rhel9cis_rule_3_3_6: true rhel9cis_rule_3_3_7: true rhel9cis_rule_3_3_8: true rhel9cis_rule_3_3_9: true -rhel9cis_rule_3_3_10: true -rhel9cis_rule_3_3_11: true +rhel9cis_rule_3_4_1_1: true +rhel9cis_rule_3_4_1_2: true +rhel9cis_rule_3_4_2_1: true +rhel9cis_rule_3_4_2_2: true +rhel9cis_rule_3_4_2_3: true +rhel9cis_rule_3_4_2_4: true +rhel9cis_rule_3_4_2_5: true +rhel9cis_rule_3_4_2_6: true +rhel9cis_rule_3_4_2_7: true -## Section 4 Fixes -# Section 4 rules are Logging and Auditing (Configure System Accounting (auditd), -# Configure Data Retention, and Configure Logging) -# Firewall utility -rhel9cis_rule_4_1_1: true -rhel9cis_rule_4_1_2: true -# Configure firewalld -rhel9cis_rule_4_2_1: true -rhel9cis_rule_4_2_2: true -# Configure nftables -rhel9cis_rule_4_3_1: true -rhel9cis_rule_4_3_2: true -rhel9cis_rule_4_3_3: true -rhel9cis_rule_4_3_4: true +# Section 4 rules +rhel9cis_rule_4_1_1_1: true +rhel9cis_rule_4_1_1_2: true +rhel9cis_rule_4_1_1_3: true +rhel9cis_rule_4_1_1_4: true +rhel9cis_rule_4_1_2_1: true +rhel9cis_rule_4_1_2_2: true +rhel9cis_rule_4_1_2_3: true +rhel9cis_rule_4_1_3_1: true +rhel9cis_rule_4_1_3_2: true +rhel9cis_rule_4_1_3_3: true +rhel9cis_rule_4_1_3_4: true +rhel9cis_rule_4_1_3_5: true +rhel9cis_rule_4_1_3_6: true +rhel9cis_rule_4_1_3_7: true +rhel9cis_rule_4_1_3_8: true +rhel9cis_rule_4_1_3_9: true +rhel9cis_rule_4_1_3_10: true +rhel9cis_rule_4_1_3_11: true +rhel9cis_rule_4_1_3_12: true +rhel9cis_rule_4_1_3_13: true +rhel9cis_rule_4_1_3_14: true +rhel9cis_rule_4_1_3_15: true +rhel9cis_rule_4_1_3_16: true +rhel9cis_rule_4_1_3_17: true +rhel9cis_rule_4_1_3_18: true +rhel9cis_rule_4_1_3_19: true +rhel9cis_rule_4_1_3_20: true +rhel9cis_rule_4_1_3_21: true +rhel9cis_rule_4_1_4_1: true +rhel9cis_rule_4_1_4_2: true +rhel9cis_rule_4_1_4_3: true +rhel9cis_rule_4_1_4_4: true +rhel9cis_rule_4_1_4_5: true +rhel9cis_rule_4_1_4_6: true +rhel9cis_rule_4_1_4_7: true +rhel9cis_rule_4_1_4_8: true +rhel9cis_rule_4_1_4_9: true +rhel9cis_rule_4_1_4_10: true +rhel9cis_rule_4_2_1_1: true +rhel9cis_rule_4_2_1_2: true +rhel9cis_rule_4_2_1_3: true +rhel9cis_rule_4_2_1_4: true +rhel9cis_rule_4_2_1_5: true +rhel9cis_rule_4_2_1_6: true +rhel9cis_rule_4_2_1_7: true +rhel9cis_rule_4_2_2_1_1: true +rhel9cis_rule_4_2_2_1_2: true +rhel9cis_rule_4_2_2_1_3: true +rhel9cis_rule_4_2_2_1_4: true +rhel9cis_rule_4_2_2_2: true +rhel9cis_rule_4_2_2_3: true +rhel9cis_rule_4_2_2_4: true +rhel9cis_rule_4_2_2_5: true +rhel9cis_rule_4_2_2_6: true +rhel9cis_rule_4_2_2_7: true +rhel9cis_rule_4_2_3: true +rhel9cis_rule_4_3: true -## Section 5 Fixes -# Section 5 rules control Access, Authentication, and Authorization (Configure time-based job schedulers, -# Configure sudo, Configure SSH Server, Configure PAM and User Accounts and Environment) -# Configure SSH Server +# Section 5 rules rhel9cis_rule_5_1_1: true rhel9cis_rule_5_1_2: true rhel9cis_rule_5_1_3: true @@ -357,20 +265,6 @@ rhel9cis_rule_5_1_6: true rhel9cis_rule_5_1_7: true rhel9cis_rule_5_1_8: true rhel9cis_rule_5_1_9: true -rhel9cis_rule_5_1_10: true -rhel9cis_rule_5_1_11: true -rhel9cis_rule_5_1_12: true -rhel9cis_rule_5_1_13: true -rhel9cis_rule_5_1_14: true -rhel9cis_rule_5_1_15: true -rhel9cis_rule_5_1_16: true -rhel9cis_rule_5_1_17: true -rhel9cis_rule_5_1_18: true -rhel9cis_rule_5_1_19: true -rhel9cis_rule_5_1_20: true -rhel9cis_rule_5_1_21: true -rhel9cis_rule_5_1_22: true -# 5.2 Configure Privilege Escalation rhel9cis_rule_5_2_1: true rhel9cis_rule_5_2_2: true rhel9cis_rule_5_2_3: true @@ -378,1148 +272,433 @@ rhel9cis_rule_5_2_4: true rhel9cis_rule_5_2_5: true rhel9cis_rule_5_2_6: true rhel9cis_rule_5_2_7: true -# 5.3.1.x Configure PAM software packages -rhel9cis_rule_5_3_1_1: true -rhel9cis_rule_5_3_1_2: true -rhel9cis_rule_5_3_1_3: true -# 5.3.2 Configure authselect -rhel9cis_rule_5_3_2_1: true -rhel9cis_rule_5_3_2_2: true -rhel9cis_rule_5_3_2_3: true -rhel9cis_rule_5_3_2_4: true -rhel9cis_rule_5_3_2_5: true -# 5.3.3.1 Configure pam_faillock module -rhel9cis_rule_5_3_3_1_1: true -rhel9cis_rule_5_3_3_1_2: true -rhel9cis_rule_5_3_3_1_3: true -# 5.3.3.2 Configure pam_pwquality module -rhel9cis_rule_5_3_3_2_1: true -rhel9cis_rule_5_3_3_2_2: true -rhel9cis_rule_5_3_3_2_3: true -rhel9cis_rule_5_3_3_2_4: true -rhel9cis_rule_5_3_3_2_5: true -rhel9cis_rule_5_3_3_2_6: true -rhel9cis_rule_5_3_3_2_7: true -rhel9cis_rule_5_3_3_2_8: true -# 5.3.3.3 Configure pam_pwhistory module -# These are added as part of 5.3.2.4 using jinja2 template -rhel9cis_rule_5_3_3_3_1: true -rhel9cis_rule_5_3_3_3_2: true -rhel9cis_rule_5_3_3_3_3: true -# 5.3.3.4 Configure pam_unix module -rhel9cis_rule_5_3_3_4_1: true -rhel9cis_rule_5_3_3_4_2: true -rhel9cis_rule_5_3_3_4_3: true -rhel9cis_rule_5_3_3_4_4: true -# 5.4 User Accounts and Environment -# 5.4.1 Configure shadow password suite parameters -rhel9cis_rule_5_4_1_1: true -rhel9cis_rule_5_4_1_2: true -rhel9cis_rule_5_4_1_3: true -rhel9cis_rule_5_4_1_4: true -rhel9cis_rule_5_4_1_5: true -rhel9cis_rule_5_4_1_6: true -# 5.4.2 Configure root and system accounts and environment -rhel9cis_rule_5_4_2_1: true -rhel9cis_rule_5_4_2_2: true -rhel9cis_rule_5_4_2_3: true -rhel9cis_rule_5_4_2_4: true -rhel9cis_rule_5_4_2_5: true -rhel9cis_rule_5_4_2_6: true -rhel9cis_rule_5_4_2_7: true -rhel9cis_rule_5_4_2_8: true -# 5.4.2 Configure user default environment -rhel9cis_rule_5_4_3_1: true -rhel9cis_rule_5_4_3_2: true -rhel9cis_rule_5_4_3_3: true +rhel9cis_rule_5_2_8: true +rhel9cis_rule_5_2_9: true +rhel9cis_rule_5_2_10: true +rhel9cis_rule_5_2_12: true +rhel9cis_rule_5_2_11: true +rhel9cis_rule_5_2_13: true +rhel9cis_rule_5_2_14: true +rhel9cis_rule_5_2_15: true +rhel9cis_rule_5_2_16: true +rhel9cis_rule_5_2_17: true +rhel9cis_rule_5_2_18: true +rhel9cis_rule_5_2_19: true +rhel9cis_rule_5_2_20: true +rhel9cis_rule_5_3_1: true +rhel9cis_rule_5_3_2: true +rhel9cis_rule_5_3_3: true +rhel9cis_rule_5_3_4: true +rhel9cis_rule_5_3_5: true +rhel9cis_rule_5_3_6: true +rhel9cis_rule_5_3_7: true +rhel9cis_rule_5_4_1: true +rhel9cis_rule_5_4_2: true +rhel9cis_rule_5_5_1: true +rhel9cis_rule_5_5_2: true +rhel9cis_rule_5_5_3: true +rhel9cis_rule_5_5_4: true +rhel9cis_rule_5_5_5: true +rhel9cis_rule_5_6_1_1: true +rhel9cis_rule_5_6_1_2: true +rhel9cis_rule_5_6_1_3: true +rhel9cis_rule_5_6_1_4: true +rhel9cis_rule_5_6_1_5: true +rhel9cis_rule_5_6_2: true +rhel9cis_rule_5_6_3: true +rhel9cis_rule_5_6_4: true +rhel9cis_rule_5_6_5: true +rhel9cis_rule_5_6_6: true -## Section 6 Fixes -# Section 6 rules control Logging and Auditing -# Configure Integrity Checking +# Section 6 rules rhel9cis_rule_6_1_1: true rhel9cis_rule_6_1_2: true rhel9cis_rule_6_1_3: true -# 6.2.1 Configure systemd-journald service -rhel9cis_rule_6_2_1_1: true -rhel9cis_rule_6_2_1_2: true -rhel9cis_rule_6_2_1_3: true -rhel9cis_rule_6_2_1_4: true -# 6.2.2.x Configure journald -rhel9cis_rule_6_2_2_1_1: true -rhel9cis_rule_6_2_2_1_2: true -rhel9cis_rule_6_2_2_1_3: true -rhel9cis_rule_6_2_2_1_4: true -rhel9cis_rule_6_2_2_2: true -rhel9cis_rule_6_2_2_3: true -rhel9cis_rule_6_2_2_4: true -# 6.2.3 Configure rsyslog -rhel9cis_rule_6_2_3_1: true -rhel9cis_rule_6_2_3_2: true -rhel9cis_rule_6_2_3_3: true -rhel9cis_rule_6_2_3_4: true -rhel9cis_rule_6_2_3_5: true -rhel9cis_rule_6_2_3_6: true -rhel9cis_rule_6_2_3_7: true -rhel9cis_rule_6_2_3_8: true -# 6.2.4 Configure Logfiles -rhel9cis_rule_6_2_4_1: true -# 6.3 Configure Auditing -# 6.3.1 Configure auditd Service -rhel9cis_rule_6_3_1_1: true -rhel9cis_rule_6_3_1_2: true -rhel9cis_rule_6_3_1_3: true -rhel9cis_rule_6_3_1_4: true -# 6.3.2 Configure Data Retention -rhel9cis_rule_6_3_2_1: true -rhel9cis_rule_6_3_2_2: true -rhel9cis_rule_6_3_2_3: true -rhel9cis_rule_6_3_2_4: true -# 6.3.3 Configure auditd Rules -rhel9cis_rule_6_3_3_1: true -rhel9cis_rule_6_3_3_2: true -rhel9cis_rule_6_3_3_3: true -rhel9cis_rule_6_3_3_4: true -rhel9cis_rule_6_3_3_5: true -rhel9cis_rule_6_3_3_6: true -rhel9cis_rule_6_3_3_7: true -rhel9cis_rule_6_3_3_8: true -rhel9cis_rule_6_3_3_9: true -rhel9cis_rule_6_3_3_10: true -rhel9cis_rule_6_3_3_11: true -rhel9cis_rule_6_3_3_12: true -rhel9cis_rule_6_3_3_13: true -rhel9cis_rule_6_3_3_14: true -rhel9cis_rule_6_3_3_15: true -rhel9cis_rule_6_3_3_16: true -rhel9cis_rule_6_3_3_17: true -rhel9cis_rule_6_3_3_18: true -rhel9cis_rule_6_3_3_19: true -rhel9cis_rule_6_3_3_20: true -rhel9cis_rule_6_3_3_21: true -# 6.3.4 Configure auditd File Access -rhel9cis_rule_6_3_4_1: true -rhel9cis_rule_6_3_4_2: true -rhel9cis_rule_6_3_4_3: true -rhel9cis_rule_6_3_4_4: true -rhel9cis_rule_6_3_4_5: true -rhel9cis_rule_6_3_4_6: true -rhel9cis_rule_6_3_4_7: true -rhel9cis_rule_6_3_4_8: true -rhel9cis_rule_6_3_4_9: true -rhel9cis_rule_6_3_4_10: true - -## Section 7 Fixes -# Section 7 rules control System Maintenance -# System File Permissions -rhel9cis_rule_7_1_1: true -rhel9cis_rule_7_1_2: true -rhel9cis_rule_7_1_3: true -rhel9cis_rule_7_1_4: true -rhel9cis_rule_7_1_5: true -rhel9cis_rule_7_1_6: true -rhel9cis_rule_7_1_7: true -rhel9cis_rule_7_1_8: true -rhel9cis_rule_7_1_9: true -rhel9cis_rule_7_1_10: true -rhel9cis_rule_7_1_11: true -rhel9cis_rule_7_1_12: true -rhel9cis_rule_7_1_13: true -# 7.2 Local User and Group Settings -rhel9cis_rule_7_2_1: true -rhel9cis_rule_7_2_2: true -rhel9cis_rule_7_2_3: true -rhel9cis_rule_7_2_4: true -rhel9cis_rule_7_2_5: true -rhel9cis_rule_7_2_6: true -rhel9cis_rule_7_2_7: true -rhel9cis_rule_7_2_8: true -rhel9cis_rule_7_2_9: true +rhel9cis_rule_6_1_4: true +rhel9cis_rule_6_1_5: true +rhel9cis_rule_6_1_6: true +rhel9cis_rule_6_1_7: true +rhel9cis_rule_6_1_8: true +rhel9cis_rule_6_1_9: true +rhel9cis_rule_6_1_10: true +rhel9cis_rule_6_1_11: true +rhel9cis_rule_6_1_12: true +rhel9cis_rule_6_1_13: true +rhel9cis_rule_6_1_14: true +rhel9cis_rule_6_1_15: true +rhel9cis_rule_6_2_1: true +rhel9cis_rule_6_2_2: true +rhel9cis_rule_6_2_3: true +rhel9cis_rule_6_2_4: true +rhel9cis_rule_6_2_5: true +rhel9cis_rule_6_2_6: true +rhel9cis_rule_6_2_7: true +rhel9cis_rule_6_2_8: true +rhel9cis_rule_6_2_9: true +rhel9cis_rule_6_2_10: true +rhel9cis_rule_6_2_11: true +rhel9cis_rule_6_2_12: true +rhel9cis_rule_6_2_13: true +rhel9cis_rule_6_2_14: true +rhel9cis_rule_6_2_15: true +rhel9cis_rule_6_2_16: true ## Section 1 vars -## Ability to enable debug on mounts to assist in troubleshooting -# Mount point changes are set based upon facts created in Prelim -# these then build the variable and options that is passed to the handler to set the mount point for the controls in section1. -rhel9cis_debug_mount_data: false - -## Control 1.1.2 -# If set to `true`, rule will be implemented using the `tmp.mount` systemd-service, -# otherwise fstab configuration will be used. -# These /tmp settings will include nosuid,nodev,noexec to conform to CIS standards. +#### 1.1.2 +# These settings go into the /etc/fstab file for the /tmp mount settings +# The value must contain nosuid,nodev,noexec to conform to CIS standards +# rhel9cis_tmp_tmpfs_settings: "defaults,rw,nosuid,nodev,noexec,relatime 0 0" +# If set true uses the tmp.mount service else using fstab configuration rhel9cis_tmp_svc: false -## Control 1.2.1 -# For new systems that have not yet run update the gpg key is not yet imported -# Setting to `true` will allow a test on the package and force the import of the key -rhel9cis_force_gpg_key_import: true +#### 1.1.9 +rhel9cis_allow_autofs: false -## Control 1.2.1.3 -# When installing RHEL from authorized Red Hat source, RHEL will come with default YUM repository. NOT having a default YUM -# repo ('rhel9cis_rhel_default_repo' set as 'false'), in conjunction with 'rhel9cis_rule_enable_repogpg' set as 'True', will enable the tasks -# which check the GPG signatures for all the individual YUM repositories. +# 1.2.1 +# This is the login information for your RedHat Subscription +# DO NOT USE PLAIN TEXT PASSWORDS!!!!! +# The intent here is to use a password utility like Ansible Vault here +rhel9cis_rh_sub_user: user +rhel9cis_rh_sub_password: password + +# 1.2.2 +# Do you require rhnsd +# RedHat Satellite Subscription items +rhel9cis_rhnsd_required: false + +# 1.2.4 repo_gpgcheck rhel9cis_rhel_default_repo: true -## Control 1.2.1.3 -# When 'rhel9cis_rule_enable_repogpg' is set to 'true'(in conjunction with 'rhel9cis_rhel_default_repo':'false'), conditions are met for -# enabling the GPG signatures-check for all the individual YUM repositories. If GPG signatures-check is enabled on repositories which do not -# support it(like RedHat), installation of packages will fail. -rhel9cis_rule_enable_repogpg: true -## Control 1.3.1.3|4|5 - SELinux policy settings -# This selects type of policy; targeted or mls( multilevel ) -# mls should not be used, since it will disable unconfined policy module -# and may prevent some services from running. Requires SELinux not being disabled (by -# having 'rhel9cis_selinux_disable' var set as 'true'), otherwise setting will be ignored. -rhel9cis_selinux_pol: targeted -## Control 1.3.1.3|4|5 - SELinux policy settings -# This variable contains a specific SELinux mode, respectively: -# - 'enforcing': SELinux policy IS enforced, therefore denies operations based on SELinux policy -# rules. If system was installed with SELinux, this is enabled by default. -# - 'permissive': SELinux policy IS NOT enforced, therefore does NOT deny any operation, only -# logs AVC(Access Vector Cache) messages. RedHat docs suggest it "can be used -# briefly to check if SELinux is the culprit in preventing your application -# from working". -# CIS expects enforcing since permissive allows operations that might compromise the system. -# Even though logging still occurs. -rhel9cis_selinux_enforce: enforcing - -## Control 1.4.1 -# This variable will store the hashed GRUB bootloader password to be stored in '/boot/grub2/user.cfg' file. The default value -# must be changed to a value that may be generated with this command 'grub2-mkpasswd-pbkdf2' and must comply with -# this format: 'grub.pbkdf2.sha512...' -rhel9cis_bootloader_password_hash: 'grub.pbkdf2.sha512.changethispassword' # pragma: allowlist secret - -## Control 1.4.1 -# This variable governs whether a bootloader password should be set in '/boot/grub2/user.cfg' file. +# 1.4.2 Bootloader password +rhel9cis_bootloader_password_hash: 'grub.pbkdf2.sha512.10000.9306A36764A7BEA3BF492D1784396B27F52A71812E9955A58709F94EE70697F9BD5366F36E07DEC41B52279A056E2862A93E42069D7BBB08F5DFC2679CD43812.6C32ADA5449303AD5E67A4C150558592A05381331DE6B33463469A236871FA8E70738C6F9066091D877EF88A213C86825E093117F30E9E1BF158D0DB75E7581B' +rhel9cis_bootloader_password: random rhel9cis_set_boot_pass: true -## Controls 1.6.x and Controls 5.1.x -# This variable governs if current Ansible role should manage system-wide crypto policy. -rhel9cis_crypto_policy_ansiblemanaged: true -# This variable contains the value to be set as the system-wide crypto policy. Current rule enforces NOT USING -# 'LEGACY' value(as it is less secure, it just ensures compatibility with legacy systems), therefore -# possible values for this variable are, as explained by RedHat docs: -# -'DEFAULT': reasonable default policy for today's standards (balances usability and security) -# -'FUTURE': conservative security level that is believed to withstand any near-term future attacks -# -'FIPS': A level that conforms to the FIPS140-2 requirements -rhel9cis_crypto_policy: 'DEFAULT' -# This variable contains the value of the crypto policy module(combinations of policies and -# sub-policies) to be allowed as default setting. Allowed options are defined in 'vars/main.yml' file, -# using 'rhel9cis_allowed_crypto_policies_modules' variable, which currently are: -# - 'OSPP' -# - 'AD-SUPPORT' -# - 'AD-SUPPORT-LEGACY' -rhel9cis_crypto_policy_module: '' -## Controls 1.6.x -# This variable contains the value of the crypto policy module(combinations of policies and -# sub-policies) to be allowed as default setting. Allowed options are defined in 'vars/main.yml' file, -# using those listed in the 'rhel9cis_allowed_crypto_policies_modules' variable. -rhel9cis_additional_crypto_policy_module: '' - -## Controls: -# - 1.7.1 - Ensure message of the day is configured properly -# - 1.7.2 - Ensure local login warning banner is configured properly -# - 1.7.3 - Ensure remote login warning banner is configured properly -# This variable stores the content for the Warning Banner(relevant for issue, issue.net, motd). -rhel9cis_warning_banner: Authorized users only. All activity may be monitored and reported. -# End Banner - -## Control 1.8.x - Settings for GDM -# do not run Control 1.8.x if using a display manager different than gdm -rhel9cis_display_manager: "gdm" -# This variable governs whether rules dealing with GUI specific packages(and/or their settings) should -# be executed either to: -# - secure GDM, if GUI is needed('rhel9cis_gui: true') -# - or remove GDM and X-Windows-system, if no GUI is needed('rhel9cis_gui: false') -# The value of this variable is set automatically, if gnome is present this variable -# will always have `true` as a value, and `false` otherwise. -rhel9cis_gui: "{{ prelim_gnome_present.stat.exists | default(false) }}" -# This variable specifies the GNOME configuration database file to which configurations are written. -# (See "https://help.gnome.org/admin/system-admin-guide/stable/dconf-keyfiles.html.en") -# The default database is 'local'. +# 1.8 Gnome Desktop rhel9cis_dconf_db_name: local -# This variable governs the number of seconds of inactivity before the screen goes blank. -# Set max value for idle-delay in seconds (between 1 and 900) -rhel9cis_screensaver_idle_delay: 900 -# This variable governs the number of seconds the screen remains blank before it is locked. -# Set max value for lock-delay in seconds (between 0 and 5) -rhel9cis_screensaver_lock_delay: 5 +rhel9cis_screensaver_idle_delay: 900 # Set max value for idle-delay in seconds (between 1 and 900) +rhel9cis_screensaver_lock_delay: 5 # Set max value for lock-delay in seconds (between 0 and 5) -## Section 2. Services +# 1.10 Set crypto policy DEFAULT +# Control 1.10 states not to use LEGACY +rhel9cis_crypto_policy: "DEFAULT" -## Section 2.1 Time Synchronization - -## Control 2.1.2 Time Synchronization servers - used in template file chrony.conf.j2 -# The following variable represents a list of time servers used -# for configuring chrony, timesyncd, and ntp. -# Each list item contains two settings, `name` (the domain name of the server) and synchronization `options`. -# The default setting for the `options` is `minpoll` but `iburst` can be used, please refer to the documentation -# of the time synchronization mechanism you are using. -rhel9cis_time_synchronization_servers: - - 0.pool.ntp.org - - 1.pool.ntp.org - - 2.pool.ntp.org - - 3.pool.ntp.org -## Control 2.1.2 - Time Synchronization servers -# This variable should contain the default options to be used for every NTP server hostname defined -# within the 'rhel9cis_time_synchronization_servers' var. -rhel9cis_chrony_server_options: "minpoll 8" -# This variable, if set to 'true'(default), will inform the kernel the system clock is kept synchronized -# and the kernel will update the real-time clock every 11 minutes. Otherwise, if 'rtcsync' option is -# disabled, chronyd will not be in sync(kernel discipline is disabled, 11 minutes mode will be off). -rhel9cis_chrony_server_rtcsync: false -# This variable configures the values to be used by chronyd to gradually correct any time offset, -# by slowing down/speeding up the clock. An example of this directive usage would be: -# 'makestep 1000 10'. -# Step the system clock: -# - IF the adjustment is larger than 1000 seconds -# - but ONLY IN the first ten clock updates -rhel9cis_chrony_server_makestep: "1.0 3" -# This variable configures the minimum number of sources that need to be considered as selectable in the source -# selection algorithm before the local clock is updated. Setting minsources to a larger number can be used to -# improve the reliability, because multiple sources will need to correspond with each other. -rhel9cis_chrony_server_minsources: 2 - -### -### The set of rules that make up section 2.1, are used for ensuring that -### certain services are not installed on the OS. -### The following list of variables contain two types: the ones that end in '_services', and the ones that end in '_mask' -### in '_mask'. For completely removing a service both those variables referencing that service shall be set to 'false'. -### For masking a service the type that ends in '_mask' shall be set to 'true'. -### Set this variable to `true` to keep service `autofs`; otherwise, the service is uninstalled. -### - -########################################### - -## Controls 2.1.x - Configure Server Services -# Set this variable to `true` to keep service `autofs`; otherwise, the service is uninstalled. -rhel9cis_autofs_services: false -# Set this variable to `true` to mask service `autofs`. -rhel9cis_autofs_mask: false -# Set this variable to `true` to keep service `avahi`; otherwise, the service is uninstalled. -rhel9cis_avahi_server: false -# Set this variable to `true` to mask service `avahi`. -rhel9cis_avahi_mask: false -# Set this variable to `true` to keep service `dhcp`; otherwise, the service is uninstalled. -rhel9cis_dhcp_server: false -# Set this variable to `true` to mask service `dhcp`. -rhel9cis_dhcp_mask: false -# Set this variable to `true` to keep service `dns`; otherwise, the service is uninstalled. -rhel9cis_dns_server: false -# Set this variable to `true` to mask service `dns`. -rhel9cis_dns_mask: false -# Set this variable to `true` to keep service `dnsmasq`; otherwise, the service is uninstalled. -rhel9cis_dnsmasq_server: false -# Set this variable to `true` to mask service `dnsmasq`. -rhel9cis_dnsmasq_mask: false -# Set this variable to `true` to keep service `samba`; otherwise, the service is uninstalled. -rhel9cis_samba_server: false -# Set this variable to `true` to mask service `samba`. -rhel9cis_samba_mask: false -# Set this variable to `true` to keep service `ftp`; otherwise, the service is uninstalled. -rhel9cis_ftp_server: false -# Set this variable to `true` to mask service `ftp`. -rhel9cis_ftp_mask: false -# Set this variable to `true` to keep service `message`; otherwise, the service is uninstalled. -rhel9cis_message_server: false # This is for messaging dovecot and cyrus-imap -# Set this variable to `true` to mask service `message`. -rhel9cis_message_mask: false -# Set this variable to `true` to keep service `nfs`; otherwise, the service is uninstalled. -rhel9cis_nfs_server: true -# Set this variable to `true` to mask service `nfs`. -rhel9cis_nfs_mask: true -# Set this variable to `true` to keep service `nis`; otherwise, the service is uninstalled. -rhel9cis_nis_server: true # set to mask if nis client required -# Set this variable to `true` to mask service `nis`. -rhel9cis_nis_mask: false -# Set this variable to `true` to keep service `print`; otherwise, the service is uninstalled. -rhel9cis_print_server: false # replaces cups -# Set this variable to `true` to mask service `print`. -rhel9cis_print_mask: false -# Set this variable to `true` to keep service `rpc`; otherwise, the service is uninstalled. -rhel9cis_rpc_server: true -# Set this variable to `true` to mask service `rpc`. -rhel9cis_rpc_mask: true -# Set this variable to `true` to keep service `rsync`; otherwise, the service is uninstalled. -rhel9cis_rsync_server: false -# Set this variable to `true` to mask service `rsync`. -rhel9cis_rsync_mask: false -# Set this variable to `true` to keep service `snmp`; otherwise, the service is uninstalled. -rhel9cis_snmp_server: false -# Set this variable to `true` to mask service `snmp`. -rhel9cis_snmp_mask: false -# Set this variable to `true` to keep service `telnet`; otherwise, the service is uninstalled. -rhel9cis_telnet_server: false -# Set this variable to `true` to mask service `telnet`. -rhel9cis_telnet_mask: false -# Set this variable to `true` to keep service `tftp`; otherwise, the service is uninstalled. -rhel9cis_tftp_server: false -# Set this variable to `true` to mask service `tftp`. -rhel9cis_tftp_mask: false -# Set this variable to `true` to keep service `squid`; otherwise, the service is uninstalled. -rhel9cis_squid_server: false -# Set this variable to `true` to mask service `squid`. -rhel9cis_squid_mask: false -# Set this variable to `true` to keep service `httpd`; otherwise, the service is uninstalled. -rhel9cis_httpd_server: false -# Set this variable to `true` to mask service `httpd`. -rhel9cis_httpd_mask: false -# Set this variable to `true` to keep service `nginx`; otherwise, the service is uninstalled. -rhel9cis_nginx_server: false -# Set this variable to `true` to mask service `nginx`. -rhel9cis_nginx_mask: false -# Set this variable to `true` to keep service `xinetd`; otherwise, the service is uninstalled. -rhel9cis_xinetd_server: false -# Set this variable to `true` to mask service `xinetd`. -rhel9cis_xinetd_mask: false -# Set this variable to `true` to keep service `xwindow`; otherwise, the service is uninstalled. -rhel9cis_xwindow_server: false # will remove mask not an option - -## Control 2.1.21 - Ensure mail transfer agent is configured for local-only mode -# This variable if set to 'false', ensures that the mail transfer agent is configured for -# local-only mode. -rhel9cis_is_mail_server: false - -## Section 2.2 Service clients - -## Control - 2.2.1 - Ensure FTP client is not installed -# Set this variable to `true` to keep package `ftp`; otherwise, the package is uninstalled. -rhel9cis_ftp_client: false -## Control - 2.2.2 - Ensure LDAP client is not installed -# Set this variable to `true` to keep package `openldap-clients`; otherwise, the package is uninstalled. -rhel9cis_openldap_clients_required: false -## Control - 2.2.3 - Ensure nis client is not installed -# Set this variable to `true` to keep package `nis`(`ypbind`); otherwise, the package is uninstalled. -rhel9cis_ypbind_required: false -## Control - 2.2.4 - Ensure telnet client is not installed -# Set this variable to `true` to keep package `telnet`; otherwise, the package is uninstalled. -rhel9cis_telnet_required: false -## Control - 2.2.5 - Ensure tftp client is not installed -# Set this variable to `true` to keep package `tftp`; otherwise, the package is uninstalled. -rhel9cis_tftp_client: false - -## Section 3 vars - -## Control 3.1.1 - Ensure IPv6 status is identified -# This variable governs whether ipv6 is enabled or disabled. -rhel9cis_ipv6_required: true -# rhel9cis_ipv6_disable defines the method of disabling IPv6, sysctl vs kernel -rhel9cis_ipv6_disable_method: "sysctl" - -## Control 3.1.2 - Ensure wireless interfaces are disabled -# if wireless adapter found allow network manager to be installed -rhel9cis_install_network_manager: false -# This variable holds the name of the network manager package, and it is used -# as a conditional to implement control 3.1.2. If the network manager package -# is present on the system then the control will be implemented! -rhel9cis_network_manager_package_name: NetworkManager - -## Control 3.1.3 - Ensure bluetooth services are not in use -# Set this variable to `true` to keep service `bluetooth`; otherwise, the service is uninstalled. -rhel9cis_bluetooth_service: false -# Set this variable to `true` to mask service `bluetooth`. -rhel9cis_bluetooth_mask: false - -## Controls 3.3.x System network parameters (host only OR host and router) -# This variable governs whether specific CIS rules -# concerned with acceptance and routing of packages are skipped. +# System network parameters (host only OR host and router) rhel9cis_is_router: false -# This variable governs if the task which updates sysctl(including sysctl reload) is executed. -# NOTE: The current default value is likely to be overridden by other further tasks(via 'set_fact'). +# IPv6 required +rhel9cis_ipv6_required: true + +# AIDE +rhel9cis_config_aide: true +# AIDE cron settings +rhel9cis_aide_cron: + cron_user: root + cron_file: /etc/cron.d/aide_cron + aide_job: '/usr/sbin/aide --check' + aide_minute: 0 + aide_hour: 5 + aide_day: '*' + aide_month: '*' + aide_weekday: '*' + +# SELinux policy +rhel9cis_selinux_pol: targeted +# chose onf or enfocing or permissive +rhel9cis_selinux_enforce: enforcing + +# Whether or not to run tasks related to auditing/patching the desktop environment + +## 2. Services + +### 2.1 Time Synchronization +#### 2.1.2 Time Synchronization servers - used in template file chrony.conf.j2 +rhel9cis_time_synchronization_servers: + - 0.pool.ntp.org + - 1.pool.ntp.org + - 2.pool.ntp.org + - 3.pool.ntp.org +rhel9cis_chrony_server_options: "minpoll 8" + +### 2.2 Special Purposes +##### Service configuration booleans set true to keep service +rhel9cis_gui: false +rhel9cis_avahi_server: false +rhel9cis_cups_server: false +rhel9cis_dhcp_server: false +rhel9cis_dns_server: false +rhel9cis_dnsmasq_server: false +rhel9cis_vsftpd_server: false +rhel9cis_tftp_server: false +rhel9cis_httpd_server: false +rhel9cis_nginx_server: false +rhel9cis_dovecot_server: false +rhel9cis_imap_server: false +rhel9cis_samba_server: false +rhel9cis_squid_server: false +rhel9cis_snmp_server: false +rhel9cis_telnet_server: false +rhel9cis_is_mail_server: false +# Note the options +# Packages are used for client services and Server- only remove if you dont use the client service +# + +rhel9cis_use_nfs_server: false +rhel9cis_use_nfs_service: false + +rhel9cis_use_rpc_server: false +rhel9cis_use_rpc_service: false + +rhel9cis_use_rsync_server: false +rhel9cis_use_rsync_service: false + +#### 2.3 Service clients +rhel9cis_telnet_required: false +rhel9cis_openldap_clients_required: false +rhel9cis_tftp_client: false +rhel9cis_ftp_client: false + +## Section3 vars +## Sysctl rhel9cis_sysctl_update: false -# This variable governs if the task which flushes the IPv4 routing table is executed(forcing subsequent connections to -# use the new configuration). -# NOTE: The current default value is likely to be overridden by other further tasks(via 'set_fact'). rhel9cis_flush_ipv4_route: false -# This variable governs if the task which flushes the IPv6 routing table is executed(forcing subsequent connections to -# use the new configuration). -# NOTE: The current default value is likely to be overridden by other further tasks(via 'set_fact'). rhel9cis_flush_ipv6_route: false -## Section 4 vars - -### Firewall Service to install and configure - Options are: -# 1) either 'firewalld' -# 2) or 'nftables' +### Firewall Service - either firewalld, iptables, or nftables #### Some control allow for services to be removed or masked -#### The options are under each heading: +#### The options are under each heading #### absent = remove the package #### masked = leave package if installed and mask the service rhel9cis_firewall: firewalld -## Control 4.2.2 - Ensure firewalld loopback traffic is configured -# This variable will set the firewalld default zone(that is used for everything that is not explicitly bound/assigned -# to another zone): if there is no zone assigned to a connection, interface or source, only the default zone is used. +##### firewalld rhel9cis_default_zone: public -## Controls 4.3.x -# This variable governs if a table will be automatically created in nftables. Without a table (no default one), nftables -# will not filter network traffic, so if this variable is set to 'false' and no tables exist, an alarm will be triggered! -rhel9cis_nft_tables_autonewtable: true -# This variable stores the name of the table to be used when configuring nftables(creating chains, configuring loopback -# traffic, established connections, default deny). If 'rhel9cis_nft_tables_autonewtable' is set as true, a new table will -# be created using as name the value stored by this variable. -rhel9cis_nft_tables_tablename: filter +# These are added to demonstrate how this can be done +rhel9cis_firewalld_ports: + - number: 80 + protocol: tcp -## Control 4.3.1 - Ensure nftables base chains exist -# This variable governs if a nftables base chain(entry point for packets from the networking stack) will be automatically -# created, if needed. Without a chain, a hook for input, forward, and delete, packets that would flow through those -# chains will not be touched by nftables. +#### nftables +rhel9cis_nft_tables_autonewtable: true +rhel9cis_nft_tables_tablename: filter rhel9cis_nft_tables_autochaincreate: true -## Section 5 vars +# Warning Banner Content (issue, issue.net, motd) +rhel9cis_warning_banner: Authorized uses only. All activity may be monitored and reported. +# End Banner -## Section 5.1 - SSH +## Section4 vars +### 4.1 Configure System Accounting +#### 4.1.2 Configure Data Retention +rhel9cis_auditd: + space_left_action: email + action_mail_acct: root + admin_space_left_action: halt + max_log_file_action: keep_logs -# This value, containing the absolute filepath of the produced 'sshd' config file, allows usage of -# drop-in files('/etc/ssh/ssh_config.d/{ssh_drop_in_name}.conf', supported by RHEL9) when CIS adopts them. -# Otherwise, the default value is '/etc/ssh/ssh_config'. -rhel9cis_sshd_config_file: /etc/ssh/sshd_config - -## Control 5.1.7 - Ensure sshd access is configured -# This variable, if specified, configures a list of USER name patterns, separated by spaces, to allow SSH -# access for users whose user name matches one of the patterns. This is done -# by setting the value of `AllowUsers` option in `/etc/ssh/sshd_config` file. -# If an USER@HOST format will be used, the specified user will be allowed only on that particular host. -rhel9cis_sshd_allowusers: "{% if ansible_facts.user_id != 'root' %}{{ ansible_facts.user_id }}{% elif ansible_env.SUDO_USER is defined %}{{ ansible_env.SUDO_USER }}{% endif %}" -## Control 5.1.7 - Ensure sshd access is configured -# (String) This variable, if specified, configures a list of GROUP name patterns, separated by spaces, to allow SSH access -# for users whose primary group or supplementary group list matches one of the patterns. This is done -# by setting the value of `AllowGroups` option in `/etc/ssh/sshd_config` file. -rhel9cis_sshd_allowgroups: "" -## Control 5.1.7 - Ensure sshd access is configured -# This variable, if specified, configures a list of USER name patterns, separated by spaces, to prevent SSH access -# for users whose user name matches one of the patterns. This is done -# by setting the value of `DenyUsers` option in `/etc/ssh/sshd_config` file. -# If an USER@HOST format will be used, the specified user will be restricted only on that particular host. -rhel9cis_sshd_denyusers: "nobody" -## Control 5.1.7 - Ensure sshd access is configured -# This variable, if specified, configures a list of GROUP name patterns, separated by spaces, -# to prevent SSH access for users whose primary group or supplementary group list matches one of the patterns. This is done -# by setting the value of `DenyGroups` option in `/etc/ssh/sshd_config` file. -rhel9cis_sshd_denygroups: "" - -## Control 5.1.9 - Ensure sshd ClientAliveInterval and ClientAliveCountMax are configured -# This variable sets the maximum number of unresponsive "keep-alive" messages -# that can be sent from the server to the client before the connection is considered -# inactive and thus, closed. -rhel9cis_sshd_clientalivecountmax: 3 -# This variable sets the time interval in seconds between sending "keep-alive" -# messages from the server to the client. These types of messages are intended to -# keep the connection alive and prevent it being terminated due to inactivity. -rhel9cis_sshd_clientaliveinterval: 15 - -## Control 5.1.10 - Ensure sshd DisableForwarding is enabled -# By Default this will also disablex11 forwarding -# set 'yes' if x11 is required this can be changed to run in /etc/ssh/ssh_config.d/50-redhat.conf -# This variable's value is used in the `/etc/ssh/ssh_config.d/50-redhat.conf` file to -# disable X11Forwarding. If X11 is required, set this variable's value to `yes`! -rhel9cis_sshd_x11forwarding: 'no' - -## Control 5.1.14 - Ensure SSH LoginGraceTime is set to one minute or less -# This variable specifies the amount of seconds allowed for successful authentication to -# the SSH server. -rhel9cis_sshd_logingracetime: 60 - -## Control 5.1.15 - Ensure SSH LogLevel is appropriate -# This variable is used to control the verbosity of the logging produced by the SSH server. -# The options for setting it are as follows: -# - `QUIET`: Minimal logging; -# - `FATAL`: logs only fatal errors; -# - `ERROR`: logs error messages; -# - `INFO`: logs informational messages in addition to errors; -# - `VERBOSE`: logs a higher level of detail, including login attempts and key exchanges; -# - `DEBUG`: generates very detailed debugging information including sensitive information. -# - `DEBUG(x)`: Whereas x = debug level 1 to 3, DEBUG=DEBUG1. -rhel9cis_ssh_loglevel: INFO - -## Control 5.1.16 - Ensure sshd MaxAuthTries is configured -# The MaxAuthTries parameter specifies the maximum number of authentication -# attempts permitted per connection. When the login failure count reaches half the -# number, error messages will be written to the syslog file detailing the login failure. -rhel9cis_ssh_maxauthtries: '4' - -## Control 5.1.17 - Ensure sshd MaxStartups is configured -# The MaxStartups parameter specifies the maximum number of concurrent unauthenticated connections to the SSH daemon. -rhel9cis_ssh_maxstartups: '10:30:60' - -## Control 5.1.18 - Ensure sshd MaxSessions is configured -# This variable value specifies the maximum number of open sessions that are permitted from -# a given location. CIS recommends it to be 10 or less. -rhel9cis_ssh_maxsessions: 4 - -## Control 5.2.x - Ensure sudo log file exists -# By default, sudo logs through syslog(3). However, to specify a custom log file, the -# 'logfile' parameter will be used, setting it with current variable's value. -# This variable defines the path and file name of the sudo log file. -rhel9cis_sudolog_location: "/var/log/sudo.log" - -## Control 5.2.4 - Ensure users must provide password for escalation -# The following variable specifies a list of users that should not be required to provide a password -# for escalation. Feel free to edit it according to your needs. -rhel9cis_sudoers_exclude_nopasswd_list: - - ec2-user - - vagrant - -## Control 5.2.6 - Ensure sudo authentication timeout is configured correctly -# This variable sets the duration (in minutes) during which a user's authentication credentials -# are cached after successfully authenticating using "sudo". This allows the user to execute -# multiple commands with elevated privileges without needing to re-enter their password for each -# command within the specified time period. CIS requires a value of at most 15 minutes. -rhel9cis_sudo_timestamp_timeout: 15 - -## Control 5.2.7 - Ensure access to the 'su' command is restricted -# This variable determines the name of the group of users that are allowed to use the su command. -# CIS requires that such a group be CREATED(named according to site policy) and be kept EMPTY. -rhel9cis_sugroup: sugroup - -## Controls 5.3.x PAM and Authselect -# Do not use authselect if: -# Your host is part of Linux Identity Management. -# Joining your host to an IdM domain with the ipa-client-install command automatically configures SSSD authentication on your host. -# Your host is part of Active Directory via SSSD. -# Calling the realm join command to join your host to an Active Directory domain automatically configures SSSD authentication on your host. -rhel9cis_allow_authselect_updates: true -## Control 5.3.1.2 - Ensure latest version of authselect is installed -# The following variables controls the implementation of control 5.3.1.2. -# If you want the latest version to be installed set this variable's value -# to `true`. -rhel9cis_authselect_pkg_update: false # NOTE the risks if system is using SSSD or using ipa-client-install - -## PAM AND Authselect - -## Controls 5.3.x - -# This variable configures the name of the custom profile to be created and selected. -# To be changed from default - cis_example_profile. This setting needs to be adjusted -# in order to minimise risk. -rhel9cis_authselect_custom_profile_name: cis_example_profile -# Name of the existing authselect profile to copy - options can be found with -# ```authselect list``` on the host to be configured -rhel9cis_authselect_default_profile_to_copy: "sssd --symlink-meta" - -## Control 5.3.3.1.1 - -# This variable sets the amount of tries a password can be entered, before a user is locked. -rhel9cis_pam_faillock_deny: 5 -## Control 5.3.3.2, 5.3.2.2 -# This variable sets the amount of time a user will be unlocked after the max amount of -# password failures. -rhel9cis_pam_faillock_unlock_time: 900 - -## Control 5.3.3.1.3 - Ensure password failed attempts lockout includes root account -# This variable is used in the task that ensures that even the root account -# is included in the password failed attempts lockout measure. -# The following variable is used in the 'regexp' field. This field is used to find the -# line in the file. If the line matches the regular expression, it will be replaced -# with the line parameter's value. -rhel9cis_pamroot_lock_option: even_deny_root - -## Control 5.3.3.2.1 - Ensure password number of changed characters is configured -# This variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure password number of changed characters is configured' control. -rhel9cis_passwd_difok_file: etc/security/pwquality.conf.d/50-pwdifok.conf # pragma: allowlist secret -# This variable's value represents the minimum number of characters that must be different between -# the new password and the old password. It helps ensure that users don't create new passwords that -# are too similar to their previous ones, enhancing security. CIS states that this value should be at least 2. -rhel9cis_passwd_difok_value: 2 - -## Control 5.3.3.2.2 - Ensure minimum password length is configured -# This variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure minimum password length is configured' control. -rhel9cis_passwd_minlen_file: etc/security/pwquality.conf.d/50-pwlength.conf # pragma: allowlist secret -# This variable specifies the minimum length that a password must have to be considered valid. -# CIS states that this value should be at least 14. -rhel9cis_passwd_minlen_value: 14 - -## Control 5.3.3.2.3 - Ensure password complexity is configured -# The following variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure password complexity is configured' control. -rhel9cis_passwd_complex_file: etc/security/pwquality.conf.d/50-pwcomplexity.conf # pragma: allowlist secret -# This variable holds the options for configuring the password complexity. -# Options supported are: 'minclass' or 'credits'. -rhel9cis_passwd_complex_option: minclass # pragma: allowlist secret -# The following variable sets the password complexity via 'minclass'. The 'minclass' option provides -# the minimum number of classes of characters required in a new password. (digits, uppercase, lowercase, others). e.g. -# For example a value of 4 would mean that it requires digits, uppercase, lower case, and special characters. -rhel9cis_passwd_minclass: 4 -# The following variables set the password complexity via the 'credits' option. -# Each of the variables represents a requirement for complexity. -# The 'dcredit' variable is the maximum credit for having digits in the new password. -# If less than 0 it is the minimum number of digits in the new password. -# e.g. dcredit = -1 requires at least one digit -rhel9cis_passwd_dcredit: -1 -# The 'ucredit' variable is the maximum credit for having uppercase characters in the new password. -# If less than 0 it is the minimum number of uppercase characters in the new password. -# e.g. ucredit = -1 requires at least one uppercase character -rhel9cis_passwd_ucredit: -2 -# The 'ocredit' variable is the maximum credit for having other characters in the new password. -# If less than 0 it is the minimum number of other characters in the new password. -# e.g. ocredit = -1 requires at least one special character -rhel9cis_passwd_ocredit: 0 -# The 'lcredit' variable is the maximum credit for having lowercase characters in the new password. -# If less than 0 it is the minimum number of lowercase characters in the new password. -# e.g. lcredit = -1 requires at least one lowercase character -rhel9cis_passwd_lcredit: -2 - -## Control 5.3.3.2.4 - Ensure password same consecutive characters is configured -# This variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure password same consecutive characters is configured' control. -rhel9cis_passwd_maxrepeat_file: etc/security/pwquality.conf.d/50-pwrepeat.conf # pragma: allowlist secret -# The following variable sets the maximum number of allowed same consecutive characters in a new password. -rhel9cis_passwd_maxrepeat_value: 3 - -## Control 5.3.3.2.5 - Ensure password maximum sequential characters is configured -# This variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure password maximum sequential characters is configured' control. -rhel9cis_passwd_maxsequence_file: etc/security/pwquality.conf.d/50-pwmaxsequence.conf # pragma: allowlist secret -# The following variable sets the maximum length of monotonic character sequences in the new password. -# Examples of such sequence are '12345' or 'fedcb' . The check is disabled if the value is 0 . -rhel9cis_passwd_maxsequence_value: 3 - -## Control 5.3.3.2.6 - Ensure password dictionary check is enabled -# This variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure password dictionary check is enabled' control -rhel9cis_passwd_dictcheck_file: etc/security/pwquality.conf.d/50-pwdictcheck.conf # pragma: allowlist secret -# The following variable's value sets whether to check for the words from the cracklib dictionary. -# When set to '1', this option enables dictionary checks, ensuring that passwords are not based on common -# dictionary words, which helps prevent users from choosing easily guessable passwords. -# When set to '0', dictionary checks are disabled. CIS states that it shall always be set to '1'. -rhel9cis_passwd_dictcheck_value: 1 - -# This variable is used in one of the config files to ensure password quality checking is enforced -rhel9cis_passwd_quality_enforce_value: 1 - -## Control 5.3.3.2.7 - Ensure password quality is enforced for the root user -# This variable holds the path to the configuration file that will be created (or overwritten if already existing) -# in order to implement the 'Ensure password quality is enforced for the root user' control. -rhel9cis_passwd_quality_enforce_root_file: etc/security/pwquality.conf.d/50-pwroot.conf # pragma: allowlist secret -# The following variable enforces that the root user must adhere to the same password quality policies as other users. -rhel9cis_passwd_quality_enforce_root_value: enforce_for_root # pragma: allowlist secret - -## Control 5.3.3.3.1 - Ensure password history remember is configured -# This variable represents the number of password change cycles, after which -# a user can re-use a password. CIS requires a value of 24 or more. -rhel9cis_pamd_pwhistory_remember: 24 - -## Controls 5.3.3.4.3, 5.4.1.4 -# The following variable's value represents the hashing algorithm used -rhel9cis_passwd_hash_algo: sha512 # pragma: allowlist secret - -## Control 5.4.1.1 - Ensure password expiration is 365 days or less -# This variable governs after how many days a password expires. -# CIS requires a value of 365 or less. -rhel9cis_pass_max_days: 365 -# The following variable allows the forcing of setting user_max_days for logins. -# This can break current connecting user access -rhel9cis_force_user_maxdays: false -## Control 5.4.1.2 - Ensure minimum days between password changes is 7 or more -# This variable specifies the minimum number of days allowed between changing -# passwords. CIS requires a value of at least 1. -rhel9cis_pass_min_days: 7 -# The following variable allows the force setting of minimum days between changing the password -# This can break current connecting user access -rhel9cis_force_user_mindays: false -## Control 5.4.1.3 - Ensure password expiration warning days is 7 or more -# This variable governs, how many days before a password expires, the user will be warned. -# CIS requires a value of at least 7. -rhel9cis_pass_warn_age: 7 -# The following variable allows the forcing of number of days before warning users of password expiry -# This can break current connecting user access -rhel9cis_force_user_warnage: false - -## Control 5.4.1.5 - Ensure inactive password lock is configured -rhel9cis_inactivelock: - # This variable specifies the number of days of inactivity before an account will be locked. - # CIS requires a value of 30 days or less. - lock_days: 30 - -## Control 5.4.1.6 - Ensure all users last password change date is in the past -# Allow ansible to expire password for account with a last changed date in the future. Setting it -# to 'false' will just display users in violation, while 'true' will expire those users passwords. -rhel9cis_futurepwchgdate_autofix: true - -## Control 5.4.2.6 - Ensure root user umask is configured -# The following variable specifies the "umask" to configure for the root user. -# The user file-creation mode mask ( umask ) is used to determine the file -# permission for newly created directories and files. In Linux, the default -# permissions for any newly created directory is 0777 ( rwxrwxrwx ), and for -# any newly created file it is 0666 ( rw-rw-rw- ). The umask modifies the default -# Linux permissions by restricting (masking) these permissions. The umask is not -# simply subtracted, but is processed bitwise. Bits set in the umask are cleared -# in the resulting file mode. CIS recommends setting 'umask' to '0027' or more -# restrictive. -rhel9cis_root_umask: '0027' # 0027 or more restrictive - -## Control 5.4.2.7 - Ensure system accounts are secured | Set nologin -# The system users on this list are allowed to have a shell (e.g. applications -# that require a shell to function) -rhel9cis_system_users_shell: [] - -## Control 5.4.3.2 - Configuring user shell timeout -# This dictionary is related to ensuring the rule about user shell timeout -# This variable represents the amount of seconds a command or process is allowed to -# run before being forcefully terminated. -# CIS requires a value of at most 900 seconds. -rhel9cis_shell_session_timeout: 900 -# This variable specifies the path of the timeout setting file. -# (TMOUT setting can be set in multiple files, but only one is required for the -# rule to pass. Options are: -# - a file in `/etc/profile.d/` ending in `.s`, -# - `/etc/profile`, or -# - `/etc/bash.bashrc`. -rhel9cis_shell_session_file: /etc/profile.d/tmout.sh - -## Control 5.4.3.3 - Ensure default user umask is configured -# The following variable specifies the "umask" to set in the `/etc/bash.bashrc` and `/etc/profile`. -# The value needs to be `027` or more restrictive to comply with CIS standards. -rhel9cis_bash_umask: '0027' # 0027 or more restrictive - -## Section 6 vars - -## Control 6.1.1 - Ensure AIDE is installed -# AIDE is a file integrity checking tool, similar in nature to Tripwire. -# While it cannot prevent intrusions, it can detect unauthorized changes -# to configuration files by alerting when the files are changed. Review -# the AIDE quick start guide and AIDE documentation before proceeding. -# By setting this variable to `true`, all the settings related to AIDE -# will be applied! -rhel9cis_config_aide: true -# This variable sets a maximum allowed age of the AIDE database file until -# the file is rebuilt. If the file is older than the value below, the role -# will automatically rebuild the database file. -# e.g. options:1w = 1 week, 1d = 1day 1h = 1 hour -rhel9cis_aide_db_file_age: 1w -# If AIDE is already setup this variable forces a new database -# file to be created. -rhel9cis_aide_db_recreate: false -# This variable is used to check if there is already an existing database file -# created by AIDE on the target system. If it is not present, the role will generate -# a database file with the same name as the value of this variable. -rhel9cis_aide_db_file: /var/lib/aide/aide.db.gz - -## Control 6.1.2 - Ensure filesystem integrity is regularly checked -# The following variable sets how AIDE is scanned. -# Available options are either cron or timer. -rhel9cis_aide_scan: cron -# These are the crontab settings for periodical checking of the filesystem's integrity using AIDE. -# The sub-settings of this variable provide the parameters required to configure -# the cron job on the target system. -# Cron is a time-based job scheduling program in Unix OS, which allows tasks to be scheduled -# and executed automatically at a certain point in time. -rhel9cis_aide_cron: - # This variable represents the user account under which the cron job for AIDE will run. - cron_user: root - # This variable represents the path to the AIDE crontab file. - cron_file: /etc/cron.d/aide_cron - # This variable represents the actual command or script that the cron job - # will execute for running AIDE. - aide_job: '/usr/sbin/aide --check' - # These variables define the schedule for the cron job - # This variable governs the minute of the time of day when the AIDE cronjob is run. - # It must be in the range `0-59`. - aide_minute: 0 - # This variable governs the hour of the time of day when the AIDE cronjob is run. - # It must be in the range `0-23`. - aide_hour: 5 - # This variable governs the day of the month when the AIDE cronjob is run. - # `*` signifies that the job is run on all days; furthermore, specific days - # can be given in the range `1-31`; several days can be concatenated with a comma. - # The specified day(s) can must be in the range `1-31`. - aide_day: '*' - # This variable governs months when the AIDE cronjob is run. - # `*` signifies that the job is run in every month; furthermore, specific months - # can be given in the range `1-12`; several months can be concatenated with commas. - # The specified month(s) can must be in the range `1-12`. - aide_month: '*' - # This variable governs the weekdays, when the AIDE cronjob is run. - # `*` signifies that the job is run on all weekdays; furthermore, specific weekdays - # can be given in the range `0-7` (both `0` and `7` represent Sunday); several weekdays - # can be concatenated with commas. - aide_weekday: '*' - -## Preferred method of logging -## Controls 6.2.1.x | Configure systemd-journald service -## Controls 6.2.2.x | Configured journald -## Controls 6.2.3.x | Configure rsyslog -# This variable governs which logging service should be used, choosing between 'rsyslog' -# or 'journald'(CIS recommendation) will trigger the execution of the associated subsection, as the-best -# practices are written wholly independent of each other. -rhel9cis_syslog: rsyslog - -## Control 6.2.1.3 - Ensure journald log rotation is configured per site policy -# Current variable configures the max amount of disk space the logs will use(thus, journal files -# will not grow without bounds) -# The variables below related to journald, please set these to your site specific values -# These variable specifies how much disk space the journal may use up at most -# Specify values in bytes or use K, M, G, T, P, E as units for the specified sizes. -# See https://www.freedesktop.org/software/systemd/man/journald.conf.html for more information. -rhel9cis_journald_systemmaxuse: 10M -## Control 6.2.1.3 - Ensure journald log rotation is configured per site policy -# Current variable configures the amount of disk space to keep free for other uses. -rhel9cis_journald_systemkeepfree: 100G -## Control 6.2.1.3 - Ensure journald log rotation is configured per site policy -# This variable configures how much disk space the journal may use up at most. -# Similar with 'rhel9cis_journald_systemmaxuse', but related to runtime space. -rhel9cis_journald_runtimemaxuse: 10M -## Control 6.2.1.3 - Ensure journald log rotation is configured per site policy -# This variable configures the actual amount of disk space to keep free -# Similar with 'rhel9cis_journald_systemkeepfree', but related to runtime space. -rhel9cis_journald_runtimekeepfree: 100G -## Control 6.2.1.3 - Ensure journald log rotation is configured per site policy -# Current variable governs the settings for log retention(how long the log files will be kept). -# Thus, it specifies the maximum time to store entries in a single journal -# file before rotating to the next one. Set to 0 to turn off this feature. -# The given values is interpreted as seconds, unless suffixed with the units -# `year`, `month`, `week`, `day`, `h` or `m` to override the default time unit of seconds. -# Values are Xm, Xh, Xday, Xweek, Xmonth, Xyear, for example 2week is two weeks -# ATTENTION: Uncomment the keyword below when values are set! -rhel9cis_journald_maxfilesec: 1month - -## Control 6.2.2.1.2 - Ensure systemd-journal-upload authentication is configured -# 'rhel9cis_journal_upload_url' is the ip address to upload the journal entries to -# URL value may specify either just the hostname or both the protocol and hostname. 'https' is the default. The port -# number may be specified after a colon (":"), otherwise 19532 will be used by default. -rhel9cis_journal_upload_url: 192.168.50.42 -## Control 6.2.2.1.2 - Ensure systemd-journal-remote is configured -# This variable specifies the path to the private key file used by the remote journal -# server to authenticate itself to the client. This key is used alongside the server's -# public certificate to establish secure communication. The path below has the default -# path/file, but it is also allowed for a user to create its custom path/filename. -rhel9cis_journal_upload_serverkeyfile: "/etc/ssl/private/journal-upload.pem" -## Control 6.2.2.1.2 - Ensure systemd-journal-remote is configured -# This variable specifies the path to the public certificate file of the remote journal -# server. This certificate is used to verify the authenticity of the remote server. The path -# below has the default path/file, but it is also allowed for a user to create its custom -# path/filename. -rhel9cis_journal_servercertificatefile: "/etc/ssl/certs/journal-upload.pem" -## Control 6.2.2.1.2 - Ensure systemd-journal-remote is configured -# This variable specifies the path to a file containing one or more public certificates -# of certificate authorities (CAs) that the client trusts. These trusted certificates are used -# to validate the authenticity of the remote server's certificate. The path below has the default -## path/file, but it is also allowed for a user to create its custom path/filename. -rhel9cis_journal_trustedcertificatefile: "/etc/ssl/ca/trusted.pem" -# ATTENTION: Uncomment the keyword below when values are set! - -## Control 6.2.3.5 | PATCH | Ensure logging is configured -# This variable governs if current Ansible role should manage syslog settings -# in /etc/rsyslog.conf file, namely mail, news and misc(warn, messages) -rhel9cis_rsyslog_ansiblemanaged: true - -## Control 6.2.3.6 - Ensure rsyslog is configured to send logs to a remote log host -# This variable governs if 'rsyslog' service should be automatically configured to forward messages to a -# remote log server. If set to 'false', the configuration of the 'omfwd' plugin, used to provide forwarding -# over UDP or TCP, will not be performed. -rhel9cis_remote_log_server: false -## Control 6.2.3.6 - Ensure rsyslog is configured to send logs to a remote log host -# This variable configures the value of the 'target' parameter to be configured when enabling -# forwarding syslog messages to a remote log server, thus configuring the actual FQDN/IP address of the -# destination server. For this value to be reflected in the configuration, the variable which enables the -# automatic configuration of rsyslog forwarding must be enabled('rhel9cis_remote_log_server: true'). -rhel9cis_remote_log_host: logagg.example.com -## Control 6.2.3.6 - Ensure rsyslog is configured to send logs to a remote log host -# This variable configures the value of the 'port' parameter to be configured when enabling -# forwarding syslog messages to a remote log server. The default value for this destination port is 514. -# For this value to be reflected in the configuration, the variable which enables the -# automatic configuration of rsyslog forwarding must be enabled('rhel9cis_remote_log_server: true'). -rhel9cis_remote_log_port: 514 -## Control 6.2.3.6 - Ensure rsyslog is configured to send logs to a remote log host -# This variable configures the value("TCP"/"UDP") of the 'protocol' parameter to be configured when enabling -# forwarding syslog messages to a remote log server. The default value for the 'omfwd' plug-in is UDP. -# For this value to be reflected in the configuration, the variable which enables the -# automatic configuration of rsyslog forwarding must be enabled('rhel9cis_remote_log_server: true'). -rhel9cis_remote_log_protocol: tcp -## Control 6.2.3.6 - Ensure rsyslog is configured to send logs to a remote log host -# This variable governs how often an action is retried(value is passed to 'action.resumeRetryCount' parameter) before -# it is considered to have failed(that roughly translates to discarded messages). The default value is 0, but -# when set to "-1"(eternal), this setting would prevent rsyslog from dropping messages when retrying to connect -# if server is not responding. For this value to be reflected in the configuration, the variable which enables the -# automatic configuration of rsyslog forwarding must be enabled('rhel9cis_remote_log_server: true'). -rhel9cis_remote_log_retrycount: 100 -## Control 6.2.3.6 - Ensure rsyslog is configured to send logs to a remote log host -# This variable configures the maximum number of messages that can be hold(value is passed to 'queue.size' parameter). -# For this value to be reflected in the configuration, the variable which enables the automatic configuration -# of rsyslog forwarding must be enabled('rhel9cis_remote_log_server: true'). -rhel9cis_remote_log_queuesize: 1000 - -## Control 6.2.3.7 - Ensure rsyslog is not configured to receive logs from a remote client -# This variable expresses whether the system is used as a log server or not. If set to: -# - 'false', current system will act as a log CLIENT, thus it should NOT receive data from other hosts. -# - 'true', current system will act as a log SERVER, enabling centralised log management(by protecting log integrity -# from local attacks on remote clients) -rhel9cis_system_is_log_server: false - -## Control 6.2.3.8 rsyslog rotate -# This variable configures whether to set your own rsyslog logrotate setting -# alternate to logrotate default settings. Please refer to logrotate options -# to match your site requirements -# This variable sets when to rotate -rhel9cis_rsyslog_logrotate_rotated_when: weekly -# This variable sets how many rotations of the file to keep -rhel9cis_rsyslog_logrotate_rotatation_keep: 4 -# The following variable defines whether to set the compress option -# or not. Setting it to `true` will carry out the setting. -rhel9cis_rsyslog_logrotate_compress: true -# The following variable defines whether to set the missingok option -# or not. Setting it to `true` will carry out the setting. -rhel9cis_rsyslog_logrotate_missingok: true -# The following variable defines whether to set the notifempty option -# or not. Setting it to `true` will carry out the setting. -rhel9cis_rsyslog_logrotate_notifempty: true -# The following variable defines whether to set extra options that can -# be defined in the `rhel9cis_rsyslog_logrotate_create_opts` variable -# The variable can be found underneath this variable, in a commented -# state. -rhel9cis_rsyslog_logrotate_create: true -# Extra options that can be added according to rsyslog documentation -# Uncomment and add the required options e.g. mode owner group -# rhel9cis_rsyslog_logrotate_create_opts: - -## Control 6.3.1.3 - Ensure audit_backlog_limit is sufficient -# This variable represents the audit backlog limit, i.e., the maximum number of audit records that the -# system can buffer in memory, if the audit subsystem is unable to process them in real-time. -# Buffering in memory is useful in situations, where the audit system is overwhelmed -# with incoming audit events, and needs to temporarily store them until they can be processed. -# This variable should be set to a sufficient value. The CIS baseline recommends at least `8192` as value. +# The audit_back_log_limit value should never be below 8192 rhel9cis_audit_back_log_limit: 8192 -## Controls 6.3.2.x - What to do when log files fill up +# The max_log_file parameter should be based on your sites policy +rhel9cis_max_log_file_size: 10 -## Control 6.3.2.1 - Ensure audit log storage size is configured -# This variable specifies the maximum size in MB that an audit log file can reach -# before it is archived or deleted to make space for the new audit data. -# This should be set based on your sites policy. CIS does not provide a specific value. -rhel9cis_auditd_max_log_file_size: 10 +### 4.1.3.x audit template +update_audit_template: false -## Control 6.3.2.2 - Ensure audit logs are not automatically deleted -# This variable determines what action the audit system should take when the maximum -# size of a log file is reached. -# The options for setting this variable are as follows: -# - `ignore`: the system does nothing when the size of a log file is full; -# - `syslog`: a message is sent to the system log indicating the problem; -# - `suspend`: the system suspends recording audit events until the log file is cleared or rotated; -# - `rotate`: the log file is rotated (archived) and a new empty log file is created; -# - `keep_logs`: the system attempts to keep as many logs as possible without violating disk space constraints. -# CIS prescribes the value `keep_logs`. -rhel9cis_auditd_max_log_file_action: keep_logs - -## Control 6.3.2.3 - Ensure system is disabled when audit logs are full -# This variable determines how the system should act in case of issues with the disk. -# The disk_full_action parameter tells the system what action to take when no free space is -# available on the partition that holds the audit log files. -# Valid values are ignore, syslog, rotate, exec, suspend, single, and halt. -# CIS prescribes -# disk_full_action parameter: -# Set to halt - the auditd daemon will shutdown the system when the disk partition containing -# the audit logs becomes full. -# Set to single - the auditd daemon will put the computer system in single user mode when the -# disk partition containing the audit logs becomes full. -rhel9cis_auditd_disk_full_action: halt -# This variable determines how the system should act in case of issues with the disk. -# The disk_error_action parameter tells the system what action to take when an error is detected -# on the partition that holds the audit log files. -# Valid values are ignore, syslog, exec, suspend, single, and halt. -# disk_error_action parameter: -# Set to halt - the auditd daemon will shutdown the system when an error is detected on the -# partition that holds the audit log files. -# Set to single - the auditd daemon will put the computer system in single user mode when -# an error is detected on the partition that holds the audit log files. -# Set to syslog - the auditd daemon will issue no more than 5 consecutive warnings to syslog -# when an error is detected on the partition that holds the audit log files. -rhel9cis_auditd_disk_error_action: syslog - -## Control 6.3.2.4 - Ensure system warns when audit logs are low on space -# This variable tells the system what action to take when the system has detected -# that it is starting to get low on disk space. -# The options for setting this variable are as follows: -# "ignore" - the system does nothing when presented with the aforementioned issue; -# "syslog" - a message is sent to the system log about disk space running low; -# "email" - the system sends an email notification to the email address -# specified in the "action_mail_acct" variable; -# "exec" - the system executes a custom command when disk space is running -# low; -# "suspend" - the system suspends recording audit events until more space is available; -# "single" - the audit daemon will put the computer system in single user mode; -# "halt" - the system is halted when disk space is critically low; -# CIS prescribes either 'email', 'exec', `single` or `halt`. -rhel9cis_auditd_space_left_action: email -# This variable tells the system what action to take when the system has detected -# that it is low on disk space. -# The options for setting this variable are as follows: -# "ignore" - the system does nothing when presented with the aforementioned issue; -# "syslog" - a message is sent to the system log about disk space running low; -# "email" - the system sends an email notification to the email address -# specified in the "action_mail_acct" variable; -# "exec" - the system executes a custom command when disk space is running -# low; -# "suspend" - the system suspends recording audit events until more space is available; -# "single" - the audit daemon will put the computer system in single user mode; -# "halt" - the system is halted when disk space is critically low; -# CIS prescribes either `halt` or `single`. -rhel9cis_auditd_admin_space_left_action: halt - -# This value governs if the below extra-vars (found in the `rhel9cis_auditd_extra_conf`) -# for auditd should be used by the role. -rhel9cis_auditd_extra_conf_usage: false - -## Controls 6.3.3.x allow exceptions for UID in auditd config ## Advanced option found in auditd post -# This variable governs if defining user exceptions for auditd logging is acceptable. rhel9cis_allow_auditd_uid_user_exclusions: false -# This variable contains a list of uids to be excluded(users whose actions are not logged by auditd) -rhel9cis_auditd_uid_exclude: - - 1999 # This can be used to configure other keys in auditd.conf -rhel9cis_auditd_extra_conf: - # This variable governs the threshold(MegaBytes) under which the audit daemon should perform a - # specific action to alert that the system is running low on disk space. Must be lower than - # the 'space_left' variable. - admin_space_left: '10%' +rhel9cis_auditd_extra_conf: {} +# Example: +# rhel9cis_auditd_extra_conf: +# admin_space_left: '10%' -# Section 7 Vars +## Preferred method of logging +## Whether rsyslog or journald preferred method for local logging +## Affects rsyslog cis 4.2.1.3 and journald cis 4.2.2.5 +rhel9cis_syslog: rsyslog +rhel9cis_rsyslog_ansiblemanaged: true -## Control 7.1.11 - Ensure no world writable files exist -# The following variable is a toggle for enabling/disabling the automated -# removal of world-writable permissions from all files. -# Possible values are `true` and `false`. -rhel9cis_no_world_write_adjust: true +#### 4.2.1.6 remote and destation log server name +rhel9cis_remote_log_server: false +rhel9cis_remote_log_host: logagg.example.com +rhel9cis_remote_log_port: 514 +rhel9cis_remote_log_protocol: tcp +rhel9cis_remote_log_retrycount: 100 +rhel9cis_remote_log_queuesize: 1000 -## Control 7.1.12 - Ensure no files or directories without an owner and a group exist -# This variable holds the part of the command that helps detect which files and -# directories do not have an owner and an affiliated group. -rhel9cis_exclude_unowned_search_path: (! -path "/run/user/*" -a ! -path "/proc/*" -a ! -path "*/containerd/*" -a ! -path "*/kubelet/pods/*" -a ! -path "*/kubelet/plugins/*" -a ! -path "/sys/fs/cgroup/memory/*" -a ! -path "/var/*/private/*") -# The value of this variable specifies the owner that will be set for unowned files and directories. -rhel9cis_unowned_owner: root -# The value of this variable specifies the group that will be set for ungrouped files and directories. -rhel9cis_ungrouped_group: root -# This variable is a toggle for enabling/disabling the automated -# setting of an owner (specified in variable `rhel9cis_unowned_owner`) -# for all unowned files and directories. -# Possible values are `true` and `false`. -rhel9cis_ownership_adjust: true +#### 4.2.1.7 +rhel9cis_system_is_log_server: false -## Control 7.1.13 - Ensure SUID and SGID files are reviewed -# This variable is a toggle for enabling/disabling the automated removal -# of the SUID bit from all files on all mounts. -# Possible values are `true` and `false`. -rhel9cis_suid_sgid_adjust: false +# 4.2.2.1.2 +# rhel9cis_journal_upload_url is the ip address to upload the journal entries to +rhel9cis_journal_upload_url: 192.168.50.42 +# The paths below have the default paths/files, but allow user to create custom paths/filenames +rhel9cis_journal_upload_serverkeyfile: "/etc/ssl/private/journal-upload.pem" +rhel9cis_journal_servercertificatefile: "/etc/ssl/certs/journal-upload.pem" +rhel9cis_journal_trustedcertificatefile: "/etc/ssl/ca/trusted.pem" + +# 4.2.2.1 +# The variables below related to journald, please set these to your site specific values +# rhel9cis_journald_systemmaxuse is the max amount of disk space the logs will use +rhel9cis_journald_systemmaxuse: 10M +# rhel9cis_journald_systemkeepfree is the amount of disk space to keep free +rhel9cis_journald_systemkeepfree: 100G +rhel9cis_journald_runtimemaxuse: 10M +rhel9cis_journald_runtimekeepfree: 100G +# rhel9cis_journald_MaxFileSec is how long in time to keep log files. Values are Xm, Xh, Xday, Xweek, Xmonth, Xyear, for example 2week is two weeks +rhel9cis_journald_maxfilesec: 1month + +#### 4.3 +rhel9cis_logrotate: "daily" + +## Section5 vars + +# This will allow use of drop in files when CIS adopts them. +rhel9_cis_sshd_config_file: /etc/ssh/sshd_config + +rhel9cis_sshd: + clientalivecountmax: 0 + clientaliveinterval: 900 + logingracetime: 60 + # WARNING: make sure you understand the precedence when working with these values!! + # allowusers: + # allowgroups: systems dba + # denyusers: + # denygroups: + +# 5.2.5 SSH LogLevel setting. Options are INFO or VERBOSE +rhel9cis_ssh_loglevel: INFO + +# 5.2.19 SSH MaxSessions setting. Must be 4 our less +rhel9cis_ssh_maxsessions: 4 +rhel9cis_inactivelock: + lock_days: 30 + +rhel9cis_use_authconfig: false +# 5.3.1/5.3.2 Custom authselect profile settings. Settings in place now will fail, they are place holders from the control example +# Due to the way many multiple options and ways to configure this control needs to be enabled and settings adjusted to minimise risk +rhel9cis_authselect: + custom_profile_name: custom-profile + default_file_to_copy: "sssd --symlink-meta" + options: with-sudo with-faillock without-nullok + +# 5.3.1 Enable automation to create custom profile settings, using the settings above +rhel9cis_authselect_custom_profile_create: false + +# 5.3.2 Enable automation to select custom profile options, using the settings above +rhel9cis_authselect_custom_profile_select: false + +rhel9cis_pass: + max_days: 365 + min_days: 7 + warn_age: 7 + +# 5.5.1 +## PAM +rhel9cis_pam_password: + minlen: 14 + minclass: 4 + +rhel9cis_pam_faillock: + unlock_time: 900 + deny: 5 + remember: 5 -## Control 7.2.8 - Ensure local interactive user home directories are configured # UID settings for interactive users # These are discovered via logins.def if set true -rhel9cis_discover_int_uid: true -# This variable sets the minimum number from which to search for UID -# Note that the value will be dynamically overwritten if variable `rhel9cis_discover_int_uid` has -# been set to `true`. +discover_int_uid: false min_int_uid: 1000 -# This variable sets the maximum number at which the search stops for UID -# Note that the value will be dynamically overwritten if variable `rhel9cis_discover_int_uid` has -# been set to `true`. max_int_uid: 65533 -## Control 7.2.9 - Ensure local interactive user dot files access is configured -# This variable is a toggle for enabling/disabling the automated modification of -# permissions on dot files. -# Possible values are `true` and `false` -# This setting can impact a running system if not tested sufficiently -rhel9cis_dotperm_ansiblemanaged: false +# 5.3.3 var log location variable +rhel9cis_sudolog_location: "/var/log/sudo.log" + +#### 5.3.6 +rhel9cis_sudo_timestamp_timeout: 15 + +### 5.4.2 authselect and faillock +## This option is used at your own risk it will enable faillock for users +## Only to be used on a new clean system if not using authselect +## THIS CAN BREAK ACCESS EVEN FOR ROOT - UNDERSTAND RISKS ## +rhel9cis_add_faillock_without_authselect: false +# This needs to be set to ACCEPT +rhel9cis_5_4_2_risks: NEVER + +# RHEL-09-5.4.5 +# Session timeout setting file (TMOUT setting can be set in multiple files) +# Timeout value is in seconds. (60 seconds * 10 = 600) +rhel9cis_shell_session_timeout: + file: /etc/profile.d/tmout.sh + timeout: 600 +# RHEL-09-5.4.1.5 Allow ansible to expire password for account with a last changed date in the future. False will just display users in violation, true will expire those users passwords +rhel9cis_futurepwchgdate_autofix: true + +# 5.3.7 +rhel9cis_sugroup: nosugroup + +## Section6 vars + +# RHEL-09_6.1.1 +rhel9cis_rpm_audit_file: /var/tmp/rpm_file_check + +# RHEL-09_6.1.10 Allow ansible to adjust world-writable files. False will just display world-writable files, True will remove world-writable +rhel9cis_no_world_write_adjust: true +rhel9cis_passwd_label: "{{ (this_item | default(item)).id }}: {{ (this_item | default(item)).dir }}" + +# 6.2.16 +## Dont follow symlinks for changes to user home directory thanks to @dulin-gnet and comminty for rhel8-cis reedbacj +rhel_09_6_2_16_home_follow_symlinks: false + +#### Goss Configuration Settings #### +# Set correct env for the run_audit.sh script from https://github.com/ansible-lockdown/{{ benchmark }}-Audit.git" +audit_run_script_environment: + AUDIT_BIN: "{{ audit_bin }}" + AUDIT_FILE: 'goss.yml' + AUDIT_CONTENT_LOCATION: "{{ audit_out_dir }}" + +### Goss binary settings ### +goss_version: + release: v0.3.21 + checksum: 'sha256:9a9200779603acf0353d2c0e85ae46e083596c10838eaf4ee050c924678e4fe3' +audit_bin_path: /usr/local/bin/ +audit_bin: "{{ audit_bin_path }}goss" +audit_format: json + +# if get_goss_file == download change accordingly +goss_url: "https://github.com/goss-org/goss/releases/download/{{ goss_version.release }}/goss-linux-amd64" + +## if get_goss_file - copy the following needs to be updated for your environment +## it is expected that it will be copied from somewhere accessible to the control node +## e.g copy from ansible control node to remote host +copy_goss_from_path: /some/accessible/path + +### Goss Audit Benchmark file ### +## managed by the control audit_content +# git +audit_file_git: "https://github.com/ansible-lockdown/{{ benchmark }}-Audit.git" +audit_git_version: "benchmark_{{ benchmark_version }}" + +# copy: +audit_local_copy: "some path to copy from" + +# get_url: +audit_files_url: "some url maybe s3?" + +## Goss configuration information +# Where the goss configs and outputs are stored +audit_out_dir: '/opt' +audit_conf_dir: "{{ audit_out_dir }}/{{ benchmark }}-Audit/" +pre_audit_outfile: "{{ audit_out_dir }}/{{ ansible_hostname }}-{{ benchmark }}_pre_scan_{{ ansible_date_time.epoch }}.{{ audit_format }}" +post_audit_outfile: "{{ audit_out_dir }}/{{ ansible_hostname }}-{{ benchmark }}_post_scan_{{ ansible_date_time.epoch }}.{{ audit_format }}" + +## The following should not need changing +goss_file: "{{ audit_conf_dir }}goss.yml" +audit_vars_path: "{{ audit_conf_dir }}/vars/{{ ansible_hostname }}.yml" +audit_results: | + The pre remediation results are: {{ pre_audit_summary }}. + The post remediation results are: {{ post_audit_summary }}. + Full breakdown can be found in {{ audit_out_dir }} diff --git a/files/fs_with_cves.sh b/files/fs_with_cves.sh deleted file mode 100644 index a2bc1b7..0000000 --- a/files/fs_with_cves.sh +++ /dev/null @@ -1,56 +0,0 @@ -#! /usr/bin/env bash - -# Based on original Script provided by CIS -# CVEs correct at time of creation - April2024 - -{ - a_output=(); a_output2=(); a_modprope_config=(); a_excluded=(); a_available_modules=() - a_ignore=("xfs" "vfat" "ext2" "ext3" "ext4") - a_cve_exists=("afs" "ceph" "cifs" "exfat" "ext" "fat" "fscache" "fuse" "gfs2" "nfs_common" "nfsd" "smbfs_common") - f_module_chk() - { - l_out2=""; grep -Pq -- "\b$l_mod_name\b" <<< "${a_cve_exists[*]}" && l_out2=" <- CVE exists!" - if ! grep -Pq -- '\bblacklist\h+'"$l_mod_name"'\b' <<< "${a_modprope_config[*]}"; then - a_output2+=(" - Kernel module: \"$l_mod_name\" is not fully disabled $l_out2") - elif ! grep -Pq -- '\binstall\h+'"$l_mod_name"'\h+\/bin\/(false|true)\b' <<< "${a_modprope_config[*]}"; then - a_output2+=(" - Kernel module: \"$l_mod_name\" is not fully disabled $l_out2") - fi - if lsmod | grep "$l_mod_name" &> /dev/null; then # Check if the module is currently loaded - l_output2+=(" - Kernel module: \"$l_mod_name\" is loaded" "") - fi - } - while IFS= read -r -d $'\0' l_module_dir; do - a_available_modules+=("$(basename "$l_module_dir")") - done < <(find "$(readlink -f /lib/modules/"$(uname -r)"/kernel/fs)" -mindepth 1 -maxdepth 1 -type d ! -empty -print0) - while IFS= read -r l_exclude; do - if grep -Pq -- "\b$l_exclude\b" <<< "${a_cve_exists[*]}"; then - a_output2+=(" - ** WARNING: kernel module: \"$l_exclude\" has a CVE and is currently mounted! **") - elif - grep -Pq -- "\b$l_exclude\b" <<< "${a_available_modules[*]}"; then - a_output+=(" - Kernel module: \"$l_exclude\" is currently mounted - do NOT unload or disable") - fi - ! grep -Pq -- "\b$l_exclude\b" <<< "${a_ignore[*]}" && a_ignore+=("$l_exclude") - done < <(findmnt -knD | awk '{print $2}' | sort -u) - while IFS= read -r l_config; do - a_modprope_config+=("$l_config") - done < <(modprobe --showconfig | grep -P '^\h*(blacklist|install)') - for l_mod_name in "${a_available_modules[@]}"; do # Iterate over all filesystem modules - [[ "$l_mod_name" =~ overlay ]] && l_mod_name="${l_mod_name::-2}" - if grep -Pq -- "\b$l_mod_name\b" <<< "${a_ignore[*]}"; then - a_excluded+=(" - Kernel module: \"$l_mod_name\"") - else - f_module_chk - fi - done -# Output findings - - echo "### Script can be found at ${BASH_SOURCE} ##" - if [ "${#a_output2[@]}" -le 0 ]; then - printf '%s\n' "" " - No unused filesystem kernel modules are enabled" "${a_output[@]}" "" - else - printf '%s\n' "" "-- Audit Result: --" " ** REVIEW the following **" "${a_output2[@]}" - # Changed return value to capture error - exit 99 - #[ "${#a_output[@]}" -gt 0 ] && printf '%s\n' "" "-- Correctly set: --" "${a_output[@]}" "" - fi -} diff --git a/handlers/main.yml b/handlers/main.yml index 1ef6ccf..c4b27e7 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -1,273 +1,105 @@ --- # handlers file for RHEL9-CIS -- name: "Adding options for /tmp" - when: not rhel9cis_tmp_svc - vars: - mount_point: '/tmp' - ansible.posix.mount: - path: "{{ mount_point }}" - src: "{{ prelim_mount_point_fs_and_options[mount_point]['src'] }}" - state: present - fstype: "{{ prelim_mount_point_fs_and_options[mount_point]['fs_type'] }}" - opts: "{{ prelim_mount_point_fs_and_options[mount_point]['options'] | unique | join(',') }}" - listen: "Remount /tmp" - -- name: "Remounting /tmp" - vars: - mount_point: '/tmp' - ansible.posix.mount: - path: "{{ mount_point }}" - state: remounted - listen: "Remount /tmp" - -- name: "Remounting /tmp systemd" - vars: - mount_point: '/tmp' - ansible.builtin.systemd: - name: tmp.mount - state: restarted - daemon_reload: true - listen: "Remount /tmp" - -- name: "Adding options for /dev/shm" - vars: - mount_point: '/dev/shm' - ansible.posix.mount: - path: "{{ mount_point }}" - src: "{{ prelim_mount_point_fs_and_options[mount_point]['src'] }}" - state: present - fstype: "{{ prelim_mount_point_fs_and_options[mount_point]['fs_type'] }}" - opts: "{{ prelim_mount_point_fs_and_options[mount_point]['options'] | unique | join(',') }}" - listen: "Remount /dev/shm" - -- name: "Remounting /dev/shm" - vars: - mount_point: '/dev/shm' - ansible.posix.mount: - path: "{{ mount_point }}" - state: remounted - listen: "Remount /dev/shm" - -- name: "Adding options for /home" - vars: - mount_point: '/home' - ansible.posix.mount: - path: "{{ mount_point }}" - src: "{{ prelim_mount_point_fs_and_options[mount_point]['src'] }}" - state: present - fstype: "{{ prelim_mount_point_fs_and_options[mount_point]['fs_type'] }}" - opts: "{{ prelim_mount_point_fs_and_options[mount_point]['options'] | unique | join(',') }}" - listen: "Remount /home" - -- name: "Remounting /home" - vars: - mount_point: '/home' - ansible.posix.mount: - path: "{{ mount_point }}" - state: remounted - listen: "Remount /home" - -- name: "Adding options for /var" - vars: - mount_point: '/var' - ansible.posix.mount: - path: "{{ mount_point }}" - src: "{{ prelim_mount_point_fs_and_options[mount_point]['src'] }}" - state: present - fstype: "{{ prelim_mount_point_fs_and_options[mount_point]['fs_type'] }}" - opts: "{{ prelim_mount_point_fs_and_options[mount_point]['options'] | unique | join(',') }}" - listen: "Remount /var" - -- name: "Remounting /var" - vars: - mount_point: '/var' - ansible.posix.mount: - path: "{{ mount_point }}" - state: remounted - listen: "Remount /var" - -- name: "Adding options for /var/tmp" - vars: - mount_point: '/var/tmp' - ansible.posix.mount: - path: "{{ mount_point }}" - src: "{{ prelim_mount_point_fs_and_options[mount_point]['src'] }}" - state: present - fstype: "{{ prelim_mount_point_fs_and_options[mount_point]['fs_type'] }}" - opts: "{{ prelim_mount_point_fs_and_options[mount_point]['options'] | unique | join(',') }}" - listen: "Remount /var/tmp" - -- name: "Remounting /var/tmp" - vars: - mount_point: '/var/tmp' - ansible.posix.mount: - path: "{{ mount_point }}" - state: remounted - listen: "Remount /var/tmp" - -- name: "Adding options for /var/log" - vars: - mount_point: '/var/log' - ansible.posix.mount: - path: "{{ mount_point }}" - src: "{{ prelim_mount_point_fs_and_options[mount_point]['src'] }}" - state: present - fstype: "{{ prelim_mount_point_fs_and_options[mount_point]['fs_type'] }}" - opts: "{{ prelim_mount_point_fs_and_options[mount_point]['options'] | unique | join(',') }}" - listen: "Remount /var/log" - -- name: "Remounting /var/log" - vars: - mount_point: '/var/log' - ansible.posix.mount: - path: "{{ mount_point }}" - state: remounted - listen: "Remount /var/log" - -- name: "Adding options for /var/log/audit" - vars: - mount_point: '/var/log/audit' - ansible.posix.mount: - path: "{{ mount_point }}" - src: "{{ prelim_mount_point_fs_and_options[mount_point]['src'] }}" - state: present - fstype: "{{ prelim_mount_point_fs_and_options[mount_point]['fs_type'] }}" - opts: "{{ prelim_mount_point_fs_and_options[mount_point]['options'] | unique | join(',') }}" - listen: "Remount /var/log/audit" - -- name: "Remounting /var/log/audit" - vars: - mount_point: '/var/log/audit' - ansible.posix.mount: - path: "{{ mount_point }}" - state: remounted - listen: "Remount /var/log/audit" - -- name: "Remounting /boot/efi" - vars: - mount_point: '/boot/efi' - ansible.posix.mount: - path: "{{ mount_point }}" - state: remounted - notify: Change_requires_reboot - listen: "Remount /boot/efi" - - name: Reload sysctl - ansible.builtin.command: sysctl --system - changed_when: true + ansible.builtin.shell: sysctl --system + when: + - sysctl_updated.changed - name: Sysctl flush ipv4 route table - when: - - rhel9cis_flush_ipv4_route - - not system_is_container ansible.posix.sysctl: - name: net.ipv4.route.flush - value: '1' - sysctl_set: true + name: net.ipv4.route.flush + value: '1' + sysctl_set: true ignore_errors: true # noqa ignore-errors + when: + - rhel9cis_flush_ipv4_route + - not system_is_container - name: Sysctl flush ipv6 route table - when: - - rhel9cis_flush_ipv6_route - - not system_is_container ansible.posix.sysctl: - name: net.ipv6.route.flush - value: '1' - sysctl_set: true + name: net.ipv6.route.flush + value: '1' + sysctl_set: true + when: + - rhel9cis_flush_ipv6_route + - not system_is_container - name: Systemd restart tmp.mount ansible.builtin.systemd: - name: tmp.mount - daemon_reload: true - enabled: true - masked: false - state: reloaded + name: tmp.mount + daemon_reload: true + enabled: true + masked: false + state: reloaded -- name: Update Crypto Policy - ansible.builtin.set_fact: - rhel9cis_full_crypto_policy: "{{ rhel9cis_crypto_policy }}{{ rhel9cis_crypto_policy_module }}{% if rhel9cis_additional_crypto_policy_module | length > 0 %}:{{ rhel9cis_additional_crypto_policy_module }}{% endif %}" - notify: Set Crypto Policy - -- name: Set Crypto Policy - when: prelim_system_wide_crypto_policy.stdout != rhel9cis_full_crypto_policy - ansible.builtin.command: update-crypto-policies --set "{{ rhel9cis_full_crypto_policy }}" - changed_when: true - notify: - - Change_requires_reboot - - Restart sshd +- name: Remount tmp + ansible.posix.mount: + path: /tmp + state: remounted - name: Restart firewalld ansible.builtin.systemd: - name: firewalld - state: restarted + name: firewalld + state: restarted - name: Restart sshd ansible.builtin.systemd: - name: sshd - state: restarted + name: sshd + state: restarted - name: Restart postfix ansible.builtin.systemd: - name: postfix - state: restarted + name: postfix + state: restarted - name: Reload dconf - ansible.builtin.command: dconf update - changed_when: true + ansible.builtin.shell: dconf update - name: Grub2cfg - ansible.builtin.command: "grub2-mkconfig -o /boot/grub2/grub.cfg" - changed_when: true + ansible.builtin.shell: "grub2-mkconfig -o /boot/grub2/grub.cfg" ignore_errors: true # noqa ignore-errors + tags: + - skip_ansible_lint - name: Restart rsyslog ansible.builtin.systemd: - name: rsyslog - state: restarted + name: rsyslog + state: restarted - name: Restart journald ansible.builtin.systemd: - name: systemd-journald - state: restarted + name: systemd-journald + state: restarted - name: Restart systemd_journal_upload ansible.builtin.systemd: - name: systemd-journal-upload - state: restarted + name: systemd-journal-upload + state: restarted - name: Systemd daemon reload ansible.builtin.systemd: - daemon-reload: true - -- name: Authselect update - ansible.builtin.command: authselect apply-changes - changed_when: true + daemon-reload: true ## Auditd tasks note order for handlers to run - name: Auditd immutable check - ansible.builtin.command: grep -c "^-e 2" /etc/audit/rules.d/99_auditd.rules + ansible.builtin.shell: grep -c "^-e 2" /etc/audit/rules.d/99_auditd.rules changed_when: false - register: discovered_auditd_immutable_check + register: auditd_immutable_check - name: Audit immutable fact - when: discovered_auditd_immutable_check.stdout == '1' ansible.builtin.debug: - msg: "Reboot required for auditd to apply new rules as immutable set" + msg: "Reboot required for auditd to apply new rules as immutable set" notify: Change_requires_reboot + when: + - auditd_immutable_check.stdout == '1' -- name: Stop auditd process - ansible.builtin.command: systemctl kill auditd - changed_when: true - listen: Restart auditd - -- name: Start auditd process - ansible.builtin.systemd: - name: auditd - state: started - listen: Restart auditd +- name: Restart auditd + ansible.builtin.shell: service auditd restart + tags: + - skip_ansible_lint - name: Change_requires_reboot ansible.builtin.set_fact: - change_requires_reboot: true + change_requires_reboot: true diff --git a/local.yml b/local.yml new file mode 100644 index 0000000..18c2f43 --- /dev/null +++ b/local.yml @@ -0,0 +1,8 @@ +--- + +- hosts: localhost + connection: local + become: true + + roles: + - role: "{{ playbook_dir }}" diff --git a/meta/main.yml b/meta/main.yml index 8f8b65f..c60c6a7 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -1,32 +1,32 @@ --- galaxy_info: - author: "MindPoint Group" - description: "Apply the RHEL 9 CIS" - company: "MindPoint Group" - license: MIT - role_name: rhel9_cis - namespace: mindpointgroup - min_ansible_version: 2.10.1 - platforms: - - name: EL - versions: - - "9" - galaxy_tags: - - system - - security - - stig - - hardening - - benchmark - - compliance - - redhat - - complianceascode - - disa - - rhel9 - - cis - - rocky - - alma + author: "Sam Doran, Josh Springer, Daniel Shepherd, Bas Meijeri, James Cassell, Mike Renfro, DFed, George Nalen, Mark Bolwell" + description: "Apply the RHEL 9 CIS" + company: "MindPoint Group" + license: MIT + role_name: rhel9_cis + namespace: mindpointgroup + min_ansible_version: 2.10.0 + platforms: + - name: EL + versions: + - "9" + galaxy_tags: + - system + - security + - stig + - hardening + - benchmark + - compliance + - redhat + - complianceascode + - disa + - rhel9 + - cis + - rocky + - alma collections: - - community.general - - community.crypto - - ansible.posix + - community.general + - community.crypto + - ansible.posix dependencies: [] diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index 27172b2..d558e80 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -5,23 +5,23 @@ gather_facts: true vars: - role_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" - ansible_user: root - system_is_container: true - rhel9cis_selinux_disable: true - rhel9cis_rule_5_2_4: false - rhel9cis_rule_1_1_10: false - rhel9cis_firewall: "none" - rhel9cis_rule_4_1_1_1: false - rhel9cis_rule_4_1_1_2: false - rhel9cis_rule_4_1_1_3: false - rhel9cis_rule_4_1_1_4: false - rhel9cis_rule_4_2_1_2: false - rhel9cis_rule_4_2_1_4: false - rhel9cis_rule_5_1_1: false + role_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" + ansible_user: root + system_is_container: true + rhel9cis_selinux_disable: true + rhel9cis_rule_5_3_4: false + rhel9cis_rule_1_1_10: false + rhel9cis_firewall: "none" + rhel9cis_rule_4_1_1_1: false + rhel9cis_rule_4_1_1_2: false + rhel9cis_rule_4_1_1_3: false + rhel9cis_rule_4_1_1_4: false + rhel9cis_rule_4_2_1_2: false + rhel9cis_rule_4_2_1_4: false + rhel9cis_rule_5_1_1: false pre_tasks: tasks: - - name: "Include tasks" - ansible.builtin.include_role: - name: "{{ role_name }}" + - name: "Include tasks" + ansible.builtin.include_role: + name: "{{ role_name }}" diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index add4f44..55a6274 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -3,31 +3,32 @@ # https://molecule.readthedocs.io/en/latest/ driver: - name: docker + name: docker platforms: - - name: ubi9 - image: registry.access.redhat.com/ubi9/ubi-init - pre_build_image: true - volumes: - - /sys/fs/cgroup:/sys/fs/cgroup:ro - privileged: true - command: "/usr/sbin/init" - capabilities: - - SYS_ADMIN + - name: ubi9 + image: registry.access.redhat.com/ubi9/ubi-init + pre_build_image: true + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + privileged: true + command: "/usr/sbin/init" + capabilities: + - SYS_ADMIN provisioner: - name: ansible - config_options: - defaults: - interpreter_python: auto_silent - callbacks_enabled: profile_tasks, timer + name: ansible + config_options: + defaults: + interpreter_python: auto_silent + callbacks_enabled: profile_tasks, timer lint: | - set -e - yamllint . - ansible-lint - flake8 + set -e + yamllint . + ansible-lint + flake8 verifier: - name: ansible + name: ansible + diff --git a/molecule/default/verify.yml b/molecule/default/verify.yml index 936d5a8..5c57ab4 100644 --- a/molecule/default/verify.yml +++ b/molecule/default/verify.yml @@ -4,10 +4,10 @@ gather_facts: false vars: - role_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" + role_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" tasks: - - name: "Include verify tasks" - ansible.builtin.include_role: - name: "{{ role_name }}" - tasks_from: verify + - name: "Include verify tasks" + ansible.builtin.include_role: + name: "{{ role_name }}" + tasks_from: verify diff --git a/molecule/localhost/converge.yml b/molecule/localhost/converge.yml index e40f70d..6dadcfc 100644 --- a/molecule/localhost/converge.yml +++ b/molecule/localhost/converge.yml @@ -6,12 +6,13 @@ gather_facts: true vars: - ansible_user: "{{ lookup('env', 'USER') }}" - role_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" - rhel9cis_rule_5_2_4: false + ansible_user: "{{ lookup('env', 'USER') }}" + role_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" + rhel9cis_rule_5_3_4: false pre_tasks: tasks: - - name: "Include tasks" - ansible.builtin.include_role: - name: "{{ role_name }}" + - name: "Include tasks" + ansible.builtin.include_role: + name: "{{ role_name }}" + diff --git a/molecule/localhost/molecule.yml b/molecule/localhost/molecule.yml index 6b49944..9454705 100644 --- a/molecule/localhost/molecule.yml +++ b/molecule/localhost/molecule.yml @@ -3,27 +3,28 @@ # https://molecule.readthedocs.io/en/latest/ driver: - name: delegated - options: - managed: false - ansible_connection_options: - ansible_connection: local + name: delegated + options: + managed: false + ansible_connection_options: + ansible_connection: local platforms: - - name: localhost + - name: localhost provisioner: - name: ansible - config_options: - defaults: - interpreter_python: auto_silent - stdout_callback: yaml - callbacks_enabled: profile_tasks, timer + name: ansible + config_options: + defaults: + interpreter_python: auto_silent + stdout_callback: yaml + callbacks_enabled: profile_tasks, timer lint: | - set -e - yamllint . - ansible-lint - flake8 + set -e + yamllint . + ansible-lint + flake8 verifier: - name: ansible + name: ansible + diff --git a/molecule/localhost/verify.yml b/molecule/localhost/verify.yml index 31cc859..58afa46 100644 --- a/molecule/localhost/verify.yml +++ b/molecule/localhost/verify.yml @@ -5,10 +5,10 @@ become: true vars: - role_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" + role_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" tasks: - - name: "Include verify tasks" - ansible.builtin.include_role: - name: "{{ role_name }}" - tasks_from: verify + - name: "Include verify tasks" + ansible.builtin.include_role: + name: "{{ role_name }}" + tasks_from: verify diff --git a/molecule/wsl/converge.yml b/molecule/wsl/converge.yml index 5128600..0f5f3e6 100644 --- a/molecule/wsl/converge.yml +++ b/molecule/wsl/converge.yml @@ -6,21 +6,22 @@ gather_facts: true vars: - ansible_user: "{{ lookup('env', 'USER') }}" - system_is_container: true - rhel8cis_selinux_disable: true - role_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" - rhel8cis_rule_5_3_4: false - rhel8cis_rule_1_1_10: false - rhel8cis_rsyslog_ansiblemanaged: false - rhel8cis_rule_3_4_1_3: false - rhel8cis_rule_3_4_1_4: false - rhel8cis_rule_4_2_1_2: false - rhel8cis_rule_4_2_1_4: false - rhel8cis_rule_5_1_1: false + ansible_user: "{{ lookup('env', 'USER') }}" + system_is_container: true + rhel8cis_selinux_disable: true + role_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" + rhel8cis_rule_5_3_4: false + rhel8cis_rule_1_1_10: false + rhel8cis_rsyslog_ansiblemanaged: false + rhel8cis_rule_3_4_1_3: false + rhel8cis_rule_3_4_1_4: false + rhel8cis_rule_4_2_1_2: false + rhel8cis_rule_4_2_1_4: false + rhel8cis_rule_5_1_1: false pre_tasks: tasks: - - name: "Include tasks" - ansible.builtin.include_role: - name: "{{ role_name }}" + - name: "Include tasks" + ansible.builtin.include_role: + name: "{{ role_name }}" + diff --git a/molecule/wsl/molecule.yml b/molecule/wsl/molecule.yml index 20cb713..9360997 100644 --- a/molecule/wsl/molecule.yml +++ b/molecule/wsl/molecule.yml @@ -3,26 +3,27 @@ # https://molecule.readthedocs.io/en/latest/ driver: - name: delegated - options: - managed: false - ansible_connection_options: - ansible_connection: local + name: delegated + options: + managed: false + ansible_connection_options: + ansible_connection: local platforms: - - name: localhost + - name: localhost provisioner: - name: ansible - config_options: - defaults: - interpreter_python: auto_silent - callbacks_enabled: profile_tasks, timer + name: ansible + config_options: + defaults: + interpreter_python: auto_silent + callbacks_enabled: profile_tasks, timer lint: | - set -e - yamllint . - ansible-lint - flake8 + set -e + yamllint . + ansible-lint + flake8 verifier: - name: ansible + name: ansible + diff --git a/molecule/wsl/verify.yml b/molecule/wsl/verify.yml index 936d5a8..5c57ab4 100644 --- a/molecule/wsl/verify.yml +++ b/molecule/wsl/verify.yml @@ -4,10 +4,10 @@ gather_facts: false vars: - role_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" + role_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}" tasks: - - name: "Include verify tasks" - ansible.builtin.include_role: - name: "{{ role_name }}" - tasks_from: verify + - name: "Include verify tasks" + ansible.builtin.include_role: + name: "{{ role_name }}" + tasks_from: verify diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..52cb84d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +passlib +lxml +xmltodict +jmespath +yamllint diff --git a/site.yml b/site.yml index f3f0fae..148ca0b 100644 --- a/site.yml +++ b/site.yml @@ -1,7 +1,7 @@ --- -- name: Apply ansible-lockdown hardening - hosts: all +- hosts: all become: true roles: - - role: "{{ playbook_dir }}" + + - role: "{{ playbook_dir }}" diff --git a/tasks/LE_audit_setup.yml b/tasks/LE_audit_setup.yml index d784dc1..bc929ae 100644 --- a/tasks/LE_audit_setup.yml +++ b/tasks/LE_audit_setup.yml @@ -1,31 +1,30 @@ --- -- name: Pre Audit Setup | Set audit package name - block: - - name: Pre Audit Setup | Set audit package name | 64bit - when: ansible_facts.machine == "x86_64" - ansible.builtin.set_fact: - audit_pkg_arch_name: AMD64 - - name: Pre Audit Setup | Set audit package name | ARM64 - when: (ansible_facts.machine == "arm64" or ansible_facts.machine == "aarch64") - ansible.builtin.set_fact: - audit_pkg_arch_name: ARM64 - -- name: Pre Audit Setup | Download audit binary - when: get_audit_binary_method == 'download' +- name: Download audit binary ansible.builtin.get_url: - url: "{{ audit_bin_url }}{{ audit_pkg_arch_name }}" - dest: "{{ audit_bin }}" - owner: root - group: root - checksum: "{{ audit_bin_version[audit_pkg_arch_name + '_checksum'] }}" - mode: 'u+x,go-w' + url: "{{ goss_url }}" + dest: "{{ audit_bin }}" + owner: root + group: root + checksum: "{{ goss_version.checksum }}" + mode: 0555 + when: + - get_goss_file == 'download' -- name: Pre Audit Setup | Copy audit binary - when: get_audit_binary_method == 'copy' +- name: Copy audit binary ansible.builtin.copy: - src: "{{ audit_bin_copy_location }}/goss-linux-{{ audit_pkg_arch_name }}" - dest: "{{ audit_bin }}" - owner: root - group: root - mode: 'u+x,go-w' + src: + dest: "{{ audit_bin }}" + mode: 0555 + owner: root + group: root + when: + - get_goss_file == 'copy' + +- name: Install git if not present + ansible.builtin.package: + name: git + state: present + register: git_installed + when: + - '"git" not in ansible_facts.packages' diff --git a/tasks/audit_only.yml b/tasks/audit_only.yml deleted file mode 100644 index a33cb94..0000000 --- a/tasks/audit_only.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- - -- name: Audit_only | Fetch audit files - when: - - fetch_audit_output - - audit_only - ansible.builtin.import_tasks: - file: fetch_audit_output.yml - -- name: Audit_only | Show Audit Summary - when: audit_only - ansible.builtin.debug: - msg: "{{ audit_results.split('\n') }}" - -- name: Audit_only | Stop task for host as audit_only selected - when: audit_only - ansible.builtin.meta: end_host diff --git a/tasks/auditd.yml b/tasks/auditd.yml index 9ada459..486ef31 100644 --- a/tasks/auditd.yml +++ b/tasks/auditd.yml @@ -1,61 +1,46 @@ --- -# Since auditd rules are dependent on syscalls and syscall tables are architecture specific, -# we need to update the auditd rules depending on the architecture of the system. -# This task passed the syscalls table to the auditd template and updates the auditd rules - -- name: "POST | AUDITD | Set supported_syscalls variable" - ansible.builtin.shell: ausyscall --dump | awk '{print $2}' - changed_when: false - check_mode: false - failed_when: discovered_auditd_syscalls.rc not in [ 0, 1 ] - register: discovered_auditd_syscalls - -- name: POST | AUDITD | Apply auditd template will for section 6.3.3 - only required rules will be added | stat file - ansible.builtin.stat: - path: /etc/audit/rules.d/99_auditd.rules - register: discovered_auditd_rules_file - -- name: POST | Apply auditd template for section 6.3.3.x - when: update_audit_template - vars: - supported_syscalls: "{{ discovered_auditd_syscalls.stdout_lines }}" - ansible.builtin.template: - src: audit/99_auditd.rules.j2 - dest: /etc/audit/rules.d/99_auditd.rules - owner: root - group: root - mode: 'u-x,g-wx,o-rwx' - diff: "{{ discovered_auditd_rules_file.stat.exists }}" # Only run diff if not a new file - register: discovered_auditd_rules_template_updated - notify: - - Auditd immutable check - - Audit immutable fact - - Restart auditd - -- name: POST | AUDITD | Add Warning count for changes to template file | Warn Count # noqa no-handler - when: - - discovered_auditd_rules_template_updated.changed - - discovered_auditd_rules_file.stat.exists - ansible.builtin.import_tasks: - file: warning_facts.yml - vars: - warn_control_id: 'Auditd template updated, validate as expected' - - name: POST | AUDITD | Apply auditd template will for section 4.1.3 - only required rules will be added | stat file ansible.builtin.stat: - path: /etc/audit/rules.d/98_auditd_exceptions.rules - register: discovered_auditd_exception_file + path: /etc/audit/rules.d/99_auditd.rules + register: rhel9cis_auditd_file + +- name: POST | AUDITD | Apply auditd template will for section 4.1.3 - only required rules will be added | setup file + ansible.builtin.template: + src: audit/99_auditd.rules.j2 + dest: /etc/audit/rules.d/99_auditd.rules + owner: root + group: root + mode: 0640 + diff: "{{ rhel9cis_auditd_file.stat.exists }}" # Only run diff if not a new file + register: rhel9cis_auditd_template_updated + notify: + - Auditd immutable check + - Audit immutable fact + - Restart auditd + +- name: POST | AUDITD | Add Warning count for changes to template file | Warn Count # noqa: no-handler + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: 'Auditd template updated, see diff output for details' + when: + - rhel9cis_auditd_template_updated.changed + - rhel9cis_auditd_file.stat.exists + +- name: POST | AUDITD | Apply auditd template will for section 4.1.3 - only required rules will be added | stat file + ansible.builtin.stat: + path: /etc/audit/rules.d/98_auditd_exceptions.rules + register: rhel9cis_auditd_exception_file - name: POST | Set up auditd user logging exceptions | setup file - when: - - rhel9cis_allow_auditd_uid_user_exclusions - - rhel9cis_auditd_uid_exclude | length > 0 ansible.builtin.template: - src: audit/98_auditd_exception.rules.j2 - dest: /etc/audit/rules.d/98_auditd_exceptions.rules - owner: root - group: root - mode: '0640' - diff: "{{ discovered_auditd_exception_file.stat.exists }}" + src: audit/98_auditd_exception.rules.j2 + dest: /etc/audit/rules.d/98_auditd_exceptions.rules + owner: root + group: root + mode: 0640 + diff: "{{ rhel9cis_auditd_exception_file.stat.exists }}" notify: Restart auditd + when: + - rhel9cis_allow_auditd_uid_user_exclusions + - rhel9cis_auditd_uid_exclude | length > 0 diff --git a/tasks/check_prereqs.yml b/tasks/check_prereqs.yml index b9bf2af..dcfee57 100644 --- a/tasks/check_prereqs.yml +++ b/tasks/check_prereqs.yml @@ -1,7 +1,8 @@ --- - name: "PREREQ | If required install libselinux package to manage file changes." - when: '"libselinux-python3" not in ansible_facts.packages' ansible.builtin.package: - name: libselinux-python3 - state: present + name: libselinux-python3 + state: present + when: + - '"libselinux-python3" not in ansible_facts.packages' diff --git a/tasks/fetch_audit_output.yml b/tasks/fetch_audit_output.yml deleted file mode 100644 index e440185..0000000 --- a/tasks/fetch_audit_output.yml +++ /dev/null @@ -1,47 +0,0 @@ ---- - -# Stage to copy audit output to a centralised location - -- name: "POST | FETCH | Fetch files and copy to controller" - when: audit_output_collection_method == "fetch" - ansible.builtin.fetch: - src: "{{ item }}" - dest: "{{ audit_output_destination }}" - flat: true - changed_when: true - failed_when: false - register: discovered_audit_fetch_state - loop: - - "{{ pre_audit_outfile }}" - - "{{ post_audit_outfile }}" - become: false - -# Added this option for continuity but could be changed by adjusting the variable audit_conf_dest -# Allowing backup to one location -- name: "POST | FETCH | Copy files to location available to managed node" - when: audit_output_collection_method == "copy" - ansible.builtin.copy: - src: "{{ item }}" - dest: "{{ audit_output_destination }}" - mode: 'u-x,go-wx' - flat: true - failed_when: false - register: discovered_audit_copy_state - loop: - - "{{ pre_audit_outfile }}" - - "{{ post_audit_outfile }}" - -- name: "POST | FETCH | Fetch files and copy to controller | Warning if issues with fetch_audit_files" - when: - - (audit_output_collection_method == "fetch" and not discovered_audit_fetch_state.changed) or - (audit_output_collection_method == "copy" and not discovered_audit_copy_state.changed) - block: - - name: "POST | FETCH | Fetch files and copy to controller | Warning if issues with fetch_audit_files" - ansible.builtin.debug: - msg: "Warning!! Unable to write to localhost {{ audit_output_destination }} for audit file copy" - - - name: "POST | FETCH | Fetch files and copy to controller | Warning if issues with fetch_audit_files" - vars: - warn_control_id: "FETCH_AUDIT_FILES" - ansible.builtin.import_tasks: - file: warning_facts.yml diff --git a/tasks/main.yml b/tasks/main.yml index 4d1887d..2bb0f3f 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,262 +1,190 @@ --- # tasks file for RHEL9-CIS -- name: "Check OS version and family" - when: os_check - tags: always +- name: Check OS version and family ansible.builtin.assert: - 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('9', '==') - fail_msg: "This role can only be run against Supported OSs. {{ ansible_facts.distribution }} {{ ansible_facts.distribution_major_version }} is not supported." - success_msg: "This role is running against a supported OS {{ ansible_facts.distribution }} {{ ansible_facts.distribution_major_version }}" - -- name: "Check ansible version" - tags: always - ansible.builtin.assert: - that: ansible_version.full is version_compare(min_ansible_version, '>=') - fail_msg: "You must use Ansible {{ min_ansible_version }} or greater" - success_msg: "This role is running a supported version of ansible {{ ansible_version.full }} >= {{ min_ansible_version }}" - -- name: "Setup rules if container" + that: (ansible_distribution != 'CentOS' and ansible_os_family == 'RedHat' or ansible_os_family == "Rocky") and ansible_distribution_major_version is version_compare('9', '==') + fail_msg: "This role can only be run against Supported OSs. {{ ansible_distribution }} {{ ansible_distribution_major_version }} is not supported." + success_msg: "This role is running against a supported OS {{ ansible_distribution }} {{ ansible_distribution_major_version }}" when: - - ansible_connection == 'docker' or - ansible_facts.virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + - os_check + - not system_is_ec2 tags: - - container_discovery - - always - block: - - name: "Discover and set container variable if required" - ansible.builtin.set_fact: - system_is_container: true + - always - - name: "Load variable for container" - ansible.builtin.include_vars: - file: "{{ container_vars_file }}" - - - name: "Output if discovered is a container" - when: system_is_container - ansible.builtin.debug: - msg: system has been discovered as a container - -- name: "Check crypto-policy input" +- name: Check ansible version ansible.builtin.assert: - that: rhel9cis_crypto_policy in rhel9cis_allowed_crypto_policies - fail_msg: "Crypto policy is not a permitted version" - success_msg: "Crypto policy is a permitted version" - -- name: "Check rhel9cis_bootloader_password_hash variable has been changed" - when: - - rhel9cis_set_boot_pass - - rhel9cis_rule_1_4_1 - tags: always - ansible.builtin.assert: - that: rhel9cis_bootloader_password_hash.find('grub.pbkdf2.sha512') != -1 and rhel9cis_bootloader_password_hash != 'grub.pbkdf2.sha512.changethispassword' # pragma: allowlist secret - msg: "This role will not be able to run single user password commands as rhel9cis_bootloader_password_hash variable has not been set correctly" - -- name: "Check crypto-policy module input" - when: - - rhel9cis_rule_1_6_1 - - rhel9cis_crypto_policy_module | length > 0 + that: ansible_version.full is version_compare(min_ansible_version, '>=') + fail_msg: "You must use Ansible {{ min_ansible_version }} or greater" + success_msg: "This role is running a supported version of ansible {{ ansible_version.full }} >= {{ min_ansible_version }}" tags: - - rule_1.6.1 - - crypto - - NIST800-53R5_SC-6 - ansible.builtin.assert: - that: rhel9cis_additional_crypto_policy_module in rhel9cis_allowed_crypto_policies_modules - fail_msg: "Crypto policy module is not a permitted version" - success_msg: "Crypto policy module is a permitted version" + - always -- name: "Check password set for {{ ansible_env.SUDO_USER }}" +- name: "Check password set for {{ ansible_user }}" + block: + - name: Capture current password state of "{{ ansible_user }}" + ansible.builtin.shell: "grep {{ ansible_user }} /etc/shadow | awk -F: '{print $2}'" + changed_when: false + failed_when: false + check_mode: false + register: ansible_user_password_set + + - name: "Assert that password set for {{ ansible_user }} and account not locked" + ansible.builtin.assert: + that: ansible_user_password_set.stdout | length != 0 and ansible_user_password_set.stdout != "!!" + fail_msg: "You have {{ sudo_password_rule }} enabled but the user = {{ ansible_user }} has no password set - It can break access" + success_msg: "You a password set for the {{ ansible_user }}" + vars: + sudo_password_rule: rhel9cis_rule_5_3_4 when: - - rhel9cis_rule_5_2_4 - - ansible_env.SUDO_USER is defined - - not system_is_ec2 + - rhel9cis_rule_5_3_4 + - not system_is_ec2 tags: - - user_passwd - - rule_5.2.4 - vars: - sudo_password_rule: rhel9cis_rule_5_2_4 # pragma: allowlist secret - block: - - name: "Check password set for {{ ansible_env.SUDO_USER }} | password state" # noqa name[template] - ansible.builtin.shell: "(grep {{ ansible_env.SUDO_USER }} /etc/shadow || echo 'not found:not found') | awk -F: '{print $2}'" - changed_when: false - failed_when: false - check_mode: false - register: prelim_ansible_user_password_set - - - name: "Check for local account {{ ansible_env.SUDO_USER }} | Check for local account" # noqa name[template] - when: prelim_ansible_user_password_set.stdout == "not found" - ansible.builtin.debug: - msg: "No local account found for {{ ansible_env.SUDO_USER }} user. Skipping local account checks." - - - name: "Check local account" - when: prelim_ansible_user_password_set.stdout != "not found" - block: - - name: "Check password set for {{ ansible_env.SUDO_USER }} | Assert local password set" # noqa name[template] - ansible.builtin.assert: - that: | - ( - ((prelim_ansible_user_password_set.stdout | length != 0) and (prelim_ansible_user_password_set.stdout != "!!" )) - or - (ansible_env.SUDO_USER in rhel9cis_sudoers_exclude_nopasswd_list) - ) - fail_msg: "You have {{ sudo_password_rule }} enabled but the user = {{ ansible_env.SUDO_USER }} has no password set or or the user is not included in the exception list for rule 5.2.4 - It can break access" - success_msg: "You have a password set for the {{ ansible_env.SUDO_USER }} user or the user is included in the exception list for rule 5.2.4" - - - name: "Check account is not locked for {{ ansible_env.SUDO_USER }} | Assert local account not locked" # noqa name[template] - ansible.builtin.assert: - that: (not prelim_ansible_user_password_set.stdout.startswith("!")) or (ansible_env.SUDO_USER in rhel9cis_sudoers_exclude_nopasswd_list) - fail_msg: "You have {{ sudo_password_rule }} enabled but the user = {{ ansible_env.SUDO_USER }} is locked - It can break access" - success_msg: "The local account {{ ansible_env.SUDO_USER }} is not locked or included in the exception list for rule 5.2.4" - -- name: "Check authselect profile is selected" - when: rhel9cis_allow_authselect_updates - tags: always - block: - - name: "Check authselect profile name has been updated | Ensure name from default is changed" - ansible.builtin.assert: - that: rhel9cis_authselect_custom_profile_name != 'cis_example_profile' - fail_msg: "You still have the default name for your authselect profile" - - - name: "Check authselect profile is selected | Check current profile" - ansible.builtin.command: authselect list - changed_when: false - failed_when: prelim_authselect_current_profile.rc not in [ 0, 1 ] - register: prelim_authselect_current_profile + - user_passwd - name: "Ensure root password is set" - when: rhel9cis_rule_5_4_2_4 - tags: - - level1-server - - level1-workstation - - patch - - accounts - - root - - rule_5.4.2.4 block: - - name: "Ensure root password is set" - ansible.builtin.shell: LC_ALL=C passwd -S root | grep -E "(Alternate authentication|Password set|Password locked)" - changed_when: false - failed_when: prelim_root_passwd_set.rc not in [ 0, 1 ] - register: prelim_root_passwd_set + - name: "Ensure root password is set" + ansible.builtin.shell: passwd -S root | grep "Password set, SHA512 crypt" + changed_when: false + register: root_passwd_set - - name: "Ensure root password is set" - ansible.builtin.assert: - that: prelim_root_passwd_set.rc == 0 - fail_msg: "You have rule 5.4.2.4 enabled this requires that you have a root password set" - success_msg: "You have a root password set" + - name: "Ensure root password is set" + ansible.builtin.assert: + that: root_passwd_set.rc == 0 + fail_msg: "You have rule 5.6.6 enabled this requires that you have a root password set" + success_msg: "You have a root password set" + when: + - rhel9cis_rule_5_6_6 + tags: + - level1-server + - level1-workstation + - patch + - accounts + - root + - rule_5.6.6 -- name: "Gather the package facts" - tags: always +- name: Setup rules if container + block: + - name: Discover and set container variable if required + ansible.builtin.set_fact: + system_is_container: true + + - name: Load variable for container + ansible.builtin.include_vars: + file: "{{ container_vars_file }}" + + - name: Output if discovered is a container + ansible.builtin.debug: + msg: system has been discovered as a container + when: + - system_is_container + when: + - ansible_connection == 'docker' or + ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + tags: + - container_discovery + - always + +- name: Check crypto-policy input + ansible.builtin.assert: + that: rhel9cis_crypto_policy in rhel9cis_allowed_crypto_policies + fail_msg: "Crypto policy is not a permitted version" + success_msg: "Crypto policy is a permitted version" + +- name: Check rhel9cis_bootloader_password_hash variable has been changed + ansible.builtin.assert: + that: rhel9cis_bootloader_password_hash.find('grub.pbkdf2.sha512') != -1 and rhel9cis_bootloader_password_hash != 'grub.pbkdf2.sha512.changethispassword' + msg: "This role will not be able to run single user password commands as rhel9cis_bootloader_password_hash variable has not been set correctly" + when: + - rhel9cis_set_boot_pass + - rhel9cis_rule_1_4_1 + tags: + - always + +- name: Gather the package facts ansible.builtin.package_facts: - manager: auto - -- name: "Include OS specific variables" - tags: always - ansible.builtin.include_vars: - file: "{{ ansible_facts.distribution }}.yml" - -- name: "Include preliminary steps" + manager: auto tags: - - prelim_tasks - - always - ansible.builtin.import_tasks: - file: prelim.yml + - always -- name: "Run Section 1 tasks" +- name: Include OS specific variables + ansible.builtin.include_vars: "{{ ansible_distribution }}.yml" + tags: + - always + +- name: Include preliminary steps + ansible.builtin.import_tasks: prelim.yml + tags: + - prelim_tasks + - always + +- name: run pre_remediation audit + ansible.builtin.include_tasks: pre_remediation_audit.yml + when: + - run_audit + +- name: run Section 1 tasks + ansible.builtin.import_tasks: section_1/main.yml when: rhel9cis_section1 - ansible.builtin.import_tasks: - file: section_1/main.yml + tags: + - rhel9cis_section1 -- name: "Run Section 2 tasks" +- name: run Section 2 tasks + ansible.builtin.import_tasks: section_2/main.yml when: rhel9cis_section2 - ansible.builtin.import_tasks: - file: section_2/main.yml + tags: + - rhel9cis_section2 -- name: "Run Section 3 tasks" +- name: run Section 3 tasks + ansible.builtin.import_tasks: section_3/main.yml when: rhel9cis_section3 - ansible.builtin.import_tasks: - file: section_3/main.yml + tags: + - rhel9cis_section3 -- name: "Run Section 4 tasks" +- name: run Section 4 tasks + ansible.builtin.import_tasks: section_4/main.yml when: rhel9cis_section4 - ansible.builtin.import_tasks: - file: section_4/main.yml + tags: + - rhel9cis_section4 -- name: "Run Section 5 tasks" +- name: run Section 5 tasks + ansible.builtin.import_tasks: section_5/main.yml when: rhel9cis_section5 - ansible.builtin.import_tasks: - file: section_5/main.yml + tags: + - rhel9cis_section5 -- name: "Run Section 6 tasks" +- name: run Section 6 tasks + ansible.builtin.import_tasks: section_6/main.yml when: rhel9cis_section6 - ansible.builtin.import_tasks: - file: section_6/main.yml + tags: + - rhel9cis_section6 -- name: "Run Section 7 tasks" - when: rhel9cis_section7 - ansible.builtin.import_tasks: - file: section_7/main.yml - -- name: "Run auditd logic" +- name: run auditd logic + ansible.builtin.import_tasks: auditd.yml when: update_audit_template - tags: always - ansible.builtin.import_tasks: - file: auditd.yml - -- name: "Run post remediation tasks" tags: - - post_tasks - - always - ansible.builtin.import_tasks: - file: post.yml + - always -- name: "Run post_remediation audit" - when: run_audit - tags: always - ansible.builtin.import_tasks: - file: post_remediation_audit.yml - -- name: Add ansible file showing Benchmark and levels applied if audit details not present - when: - - create_benchmark_facts - - (post_audit_summary is defined) or - (ansible_local['compliance_facts']['lockdown_audit_details']['audit_summary'] is undefined and post_audit_summary is undefined) +- name: run post remediation tasks + ansible.builtin.import_tasks: post.yml tags: - - always - - benchmark - block: - - name: Create ansible facts directory if audit facts not present - ansible.builtin.file: - path: "{{ ansible_facts_path }}" - state: directory - owner: root - group: root - mode: 'u=rwx,go=rx' + - post_tasks + - always - - name: Create ansible facts file and levels applied if audit facts not present - ansible.builtin.template: - src: etc/ansible/compliance_facts.j2 - dest: "{{ ansible_facts_path }}/compliance_facts.fact" - owner: root - group: root - mode: 'u-x,go=r' - -- name: Fetch audit files +- name: run post_remediation audit + ansible.builtin.import_tasks: post_remediation_audit.yml when: - - fetch_audit_output - - run_audit - tags: always - ansible.builtin.import_tasks: - file: fetch_audit_output.yml + - run_audit -- name: "Show Audit Summary" - when: run_audit - tags: always +- name: Show Audit Summary ansible.builtin.debug: - msg: "{{ audit_results.split('\n') }}" + msg: "{{ audit_results.split('\n') }}" + when: run_audit -- name: "If Warnings found Output count and control IDs affected" +- name: If Warnings found Output count and control IDs affected + ansible.builtin.debug: + msg: "You have {{ warn_count }} Warning(s) that require investigating that are related to the following benchmark ID(s) {{ warn_control_list }}" when: warn_count != 0 - tags: always - ansible.builtin.debug: - msg: "You have {{ warn_count }} Warning(s) that require investigating that are related to the following benchmark ID(s) {{ warn_control_list }}" + tags: + - always diff --git a/tasks/parse_etc_password.yml b/tasks/parse_etc_password.yml index c7ed865..8ff13fd 100644 --- a/tasks/parse_etc_password.yml +++ b/tasks/parse_etc_password.yml @@ -1,31 +1,32 @@ --- - name: "PRELIM | 5.5.2 | 6.2.7 | 6.2.8 | 6.2.20 | Parse /etc/passwd" - tags: always block: - - name: "PRELIM | 5.5.2 | 6.2.7 | 6.2.8 | 6.2.20 | Parse /etc/passwd" - ansible.builtin.shell: cat /etc/passwd | grep -v '^#' - changed_when: false - check_mode: false - register: prelim_capture_passwd_file + - name: "PRELIM | 5.5.2 | 6.2.7 | 6.2.8 | 6.2.20 | Parse /etc/passwd" + ansible.builtin.shell: cat /etc/passwd + changed_when: false + check_mode: false + register: rhel9cis_passwd_file_audit - - name: "PRELIM | 5.4.2 | 7.2.8 | Split passwd entries" - ansible.builtin.set_fact: - prelim_captured_passwd_data: "{{ prelim_capture_passwd_file.stdout_lines | map('regex_replace', ld_passwd_regex, ld_passwd_yaml) | map('from_yaml') | list }}" - loop: "{{ prelim_capture_passwd_file.stdout_lines }}" - vars: - ld_passwd_regex: >- - ^(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*) - ld_passwd_yaml: | # pragma: allowlist secret - id: >-4 - \g - password: >-4 - \g - uid: \g - gid: \g - gecos: >-4 - \g - dir: >-4 - \g - shell: >-4 - \g + - name: "PRELIM | 5.5.2 | 6.2.7 | 6.2.8 | 6.2.20 | Split passwd entries" + ansible.builtin.set_fact: + rhel9cis_passwd: "{{ rhel9cis_passwd_file_audit.stdout_lines | map('regex_replace', ld_passwd_regex, ld_passwd_yaml) | map('from_yaml') | list }}" + loop: "{{ rhel9cis_passwd_file_audit.stdout_lines }}" + vars: + ld_passwd_regex: >- + ^(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*) + ld_passwd_yaml: | + id: >-4 + \g + password: >-4 + \g + uid: \g + gid: \g + gecos: >-4 + \g + dir: >-4 + \g + shell: >-4 + \g + tags: + - always diff --git a/tasks/post.yml b/tasks/post.yml index 383cdf6..8e8fea7 100644 --- a/tasks/post.yml +++ b/tasks/post.yml @@ -1,49 +1,66 @@ --- +# Post tasks - name: POST | Gather the package facts after remediation - tags: always ansible.builtin.package_facts: - manager: auto + manager: auto + tags: + - always - name: POST | Update sysctl - when: - - rhel9cis_sysctl_update - - not system_is_container - - "'procps-ng' in ansible_facts.packages" ansible.builtin.template: - src: "etc/sysctl.d/{{ item }}.j2" - dest: "/etc/sysctl.d/{{ item }}" - owner: root - group: root - mode: 'go-rwx' + src: "etc/sysctl.d/{{ item }}.j2" + dest: "/etc/sysctl.d/{{ item }}" + owner: root + group: root + mode: 0600 + register: sysctl_updated notify: Reload sysctl loop: - - 60-kernel_sysctl.conf - - 60-disable_ipv6.conf - - 60-netipv4_sysctl.conf - - 60-netipv6_sysctl.conf + - 60-kernel_sysctl.conf + - 60-disable_ipv6.conf + - 60-netipv4_sysctl.conf + - 60-netipv6_sysctl.conf + when: + - rhel9cis_sysctl_update + - not system_is_container + - "'procps-ng' in ansible_facts.packages" - name: Flush handlers ansible.builtin.meta: flush_handlers - name: POST | reboot system if changes require it and not skipped - when: change_requires_reboot - tags: - - always - vars: - warn_control_id: Reboot_required block: - - name: POST | Reboot system if changes require it and not skipped - when: not skip_reboot - ansible.builtin.reboot: + - name: POST | Reboot system if changes require it and not skipped + ansible.builtin.reboot: + when: + - change_requires_reboot + - not skip_reboot - - name: POST | Warning a reboot required but skip option set - when: skip_reboot - ansible.builtin.debug: - msg: "Warning!! changes have been made that require a reboot to be implemented but skip reboot was set - Can affect compliance check results" - changed_when: true + - name: POST | Warning a reboot required but skip option set + ansible.builtin.debug: + msg: "Warning!! changes have been made that require a reboot to be implemented but skip reboot was set - Can affect compliance check results" + changed_when: true + when: + - change_requires_reboot + - skip_reboot - - name: "POST | Warning a reboot required but skip option set | warning count" - when: skip_reboot - ansible.builtin.import_tasks: - file: warning_facts.yml + - name: "POST | Warning a reboot required but skip option set | warning count" + ansible.builtin.import_tasks: warning_facts.yml + when: + - change_requires_reboot + - skip_reboot + vars: + warn_control_id: Reboot_required + tags: + - grub + - level1-server + - level1-workstation + - level2-server + - level2-workstation + - rhel9cis_section1 + - rhel9cis_section2 + - rhel9cis_section3 + - rhel9cis_section4 + - rhel9cis_section5 + - rhel9cis_section6 diff --git a/tasks/post_remediation_audit.yml b/tasks/post_remediation_audit.yml index 5e9419c..0eb7608 100644 --- a/tasks/post_remediation_audit.yml +++ b/tasks/post_remediation_audit.yml @@ -1,33 +1,44 @@ --- -- name: Post Audit | Run post_remediation {{ benchmark }} audit # noqa name[template] - ansible.builtin.shell: "umask 0022 && {{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -m {{ audit_max_concurrent }} -o {{ post_audit_outfile }} -g \"{{ group_names }}\"" # noqa yaml[line-length] - changed_when: true - environment: - AUDIT_BIN: "{{ audit_bin }}" - AUDIT_CONTENT_LOCATION: "{{ audit_conf_dest | default('/opt') }}" - AUDIT_FILE: goss.yml +- name: "Post Audit | Run post_remediation {{ benchmark }} audit" + ansible.builtin.shell: "{{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -o {{ post_audit_outfile }} -g {{ group_names }}" + environment: "{{ audit_run_script_environment | default({}) }}" + changed_when: audit_run_post_remediation.rc == 0 + register: audit_run_post_remediation + +- name: Post Audit | ensure audit files readable by users + ansible.builtin.file: + path: "{{ item }}" + mode: 0644 + state: file + loop: + - "{{ post_audit_outfile }}" + - "{{ pre_audit_outfile }}" - name: Post Audit | Capture audit data if json format - when: audit_format == "json" block: - - name: Post Audit | Capture audit data if json format - ansible.builtin.shell: grep -E '"summary-line.*Count:.*Failed' "{{ post_audit_outfile }}" | cut -d'"' -f4 - changed_when: false - register: post_audit_summary + - name: "Capture data {{ post_audit_outfile }}" + ansible.builtin.shell: "cat {{ post_audit_outfile }}" + register: post_audit + changed_when: false - - name: Post Audit | Set Fact for audit summary - ansible.builtin.set_fact: - post_audit_results: "{{ post_audit_summary.stdout }}" + - name: Capture post-audit result + ansible.builtin.set_fact: + post_audit_summary: "{{ post_audit.stdout | from_json | json_query(summary) }}" + vars: + summary: 'summary."summary-line"' + when: + - audit_format == "json" - name: Post Audit | Capture audit data if documentation format - when: audit_format == "documentation" block: - - name: Post Audit | Capture audit data if documentation format - ansible.builtin.shell: tail -2 "{{ post_audit_outfile }}" | tac | tr '\n' ' ' - changed_when: false - register: post_audit_summary + - name: "Post Audit | capture data {{ post_audit_outfile }}" + ansible.builtin.shell: "tail -2 {{ post_audit_outfile }}" + register: post_audit + changed_when: false - - name: Post Audit | Set Fact for audit summary - ansible.builtin.set_fact: - post_audit_results: "{{ post_audit_summary.stdout }}" + - name: Post Audit | Capture post-audit result + ansible.builtin.set_fact: + post_audit_summary: "{{ post_audit.stdout_lines }}" + when: + - audit_format == "documentation" diff --git a/tasks/pre_remediation_audit.yml b/tasks/pre_remediation_audit.yml index 410473e..2947e6a 100644 --- a/tasks/pre_remediation_audit.yml +++ b/tasks/pre_remediation_audit.yml @@ -1,111 +1,109 @@ --- -- name: Pre Audit Setup | Setup the LE audit - when: setup_audit - tags: setup_audit - ansible.builtin.include_tasks: - file: LE_audit_setup.yml - -- name: Pre Audit Setup | Ensure existence of {{ audit_conf_dir }} # noqa name[template] - ansible.builtin.file: - path: "{{ audit_conf_dir }}" - mode: 'go-w' - state: directory - -- name: Pre Audit Setup | If using git for content set up - when: audit_content == 'git' - block: - - name: Pre Audit Setup | Install git - ansible.builtin.package: - name: git - state: present - - - name: Pre Audit Setup | Retrieve audit content files from git - ansible.builtin.git: - repo: "{{ audit_file_git }}" - dest: "{{ audit_conf_dir }}" - version: "{{ audit_git_version }}" - -- name: Pre Audit Setup | Copy to audit content files to server - when: audit_content == 'copy' - ansible.builtin.copy: - src: "{{ audit_conf_source }}" - dest: "{{ audit_conf_dest }}" - mode: preserve - -- name: Pre Audit Setup | Unarchive audit content files on server - when: audit_content == 'archive' - ansible.builtin.unarchive: - src: "{{ audit_conf_source }}" - dest: "{{ audit_conf_dest }}" - -- name: Pre Audit Setup | Get audit content from url - when: audit_content == 'get_url' - ansible.builtin.unarchive: - src: "{{ audit_conf_source }}" - dest: "{{ audit_conf_dest }}/{{ benchmark }}-Audit" - remote_src: "{{ (audit_conf_source is contains('http')) | ternary(true, false) }}" - extra_opts: "{{ (audit_conf_source is contains('github')) | ternary('--strip-components=1', []) }}" - -- name: Pre Audit Setup | Check Goss is available - when: run_audit - block: - - name: Pre Audit Setup | Check for goss file - ansible.builtin.stat: - path: "{{ audit_bin }}" - register: prelim_goss_available - - - name: Pre Audit Setup | If audit ensure goss is available - when: not prelim_goss_available.stat.exists - ansible.builtin.assert: - that: prelim_goss_available['stat']['exists'] == true - msg: "Audit has been selected: unable to find goss binary at {{ audit_bin }}" - -- name: Pre Audit Setup | Copy ansible default vars values to test audit - when: run_audit +- name: Pre Audit | Setup the audit + ansible.builtin.include_tasks: LE_audit_setup.yml + when: + - setup_audit tags: - - goss_template - - run_audit - ansible.builtin.template: - src: ansible_vars_goss.yml.j2 - dest: "{{ audit_vars_path }}" - mode: 'go-rwx' + - setup_audit -- name: Pre Audit | Run pre_remediation audit {{ benchmark }} # noqa name[template] - ansible.builtin.shell: "umask 0022 && {{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -m {{ audit_max_concurrent }} -o {{ pre_audit_outfile }} -g \"{{ group_names }}\"" # noqa yaml[line-length] - changed_when: true - environment: - AUDIT_BIN: "{{ audit_bin }}" - AUDIT_CONTENT_LOCATION: "{{ audit_conf_dest | default('/opt') }}" - AUDIT_FILE: goss.yml +- name: "Pre Audit | Ensure {{ audit_conf_dir }} exists" + ansible.builtin.file: + path: "{{ audit_conf_dir }}" + state: directory + mode: '0755' + +- name: Pre Audit | retrieve audit content files from git + ansible.builtin.git: + repo: "{{ audit_file_git }}" + dest: "{{ audit_conf_dir }}" + version: "{{ audit_git_version }}" + when: + - audit_content == 'git' + +- name: Pre Audit | confirm audit branch vs benchmark version + ansible.builtin.debug: + msg: "Audit will run the branch {{ audit_git_version }} for this Benchmark {{ benchmark_version }}" + +- name: Pre Audit | copy to audit content files to server + ansible.builtin.copy: + src: "{{ audit_local_copy }}" + dest: "{{ audit_conf_dir }}" + mode: 0644 + when: + - audit_content == 'copy' + +- name: Pre Audit | get audit content from url + ansible.builtin.get_url: + url: "{{ audit_files_url }}" + dest: "{{ audit_conf_dir }}" + owner: root + group: root + mode: 0755 + when: + - audit_content == 'get_url' + +- name: Pre Audit | Check Goss is available + block: + - name: Pre Audit | Check for goss file + ansible.builtin.stat: + path: "{{ audit_bin }}" + register: goss_available + + - name: Pre Audit | Alert if goss not available + ansible.builtin.assert: + that: goss_available.stat.exists + fail_msg: "Audit binary file {{ audit_bin }} does not exist" + when: + - run_audit + +- name: "Pre Audit | Check whether machine is UEFI-based" + ansible.builtin.stat: + path: /sys/firmware/efi + register: rhel9_efi_boot + tags: + - goss_template + +- name: Pre Audit | Copy ansible default vars values to test audit + ansible.builtin.template: + src: ansible_vars_goss.yml.j2 + dest: "{{ audit_vars_path }}" + mode: 0600 + when: + - run_audit + tags: + - goss_template + +- name: "Pre Audit | Run pre_remediation {{ benchmark }} audit" + ansible.builtin.shell: "{{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -o {{ pre_audit_outfile }} -g {{ group_names }}" + environment: "{{ audit_run_script_environment | default({}) }}" + changed_when: audit_run_pre_remediation.rc == 0 + register: audit_run_pre_remediation - name: Pre Audit | Capture audit data if json format - when: audit_format == "json" block: - - name: Pre Audit | Capture audit data if json format - ansible.builtin.shell: grep -E '\"summary-line.*Count:.*Failed' "{{ pre_audit_outfile }}" | cut -d'"' -f4 - changed_when: false - failed_when: pre_audit_summary.stderr | length > 0 - register: pre_audit_summary + - name: "Pre Audit | capture data {{ pre_audit_outfile }}" + ansible.builtin.shell: "cat {{ pre_audit_outfile }}" + register: pre_audit + changed_when: false - - name: Pre Audit | Set Fact for audit summary - ansible.builtin.set_fact: - pre_audit_results: "{{ pre_audit_summary.stdout }}" + - name: Pre Audit | Capture pre-audit result + ansible.builtin.set_fact: + pre_audit_summary: "{{ pre_audit.stdout | from_json | json_query(summary) }}" + vars: + summary: 'summary."summary-line"' + when: + - audit_format == "json" - name: Pre Audit | Capture audit data if documentation format - when: audit_format == "documentation" block: - - name: Pre Audit | Capture audit data if documentation format - ansible.builtin.shell: tail -2 "{{ pre_audit_outfile }}" | tac | tr '\n' ' ' - changed_when: false - failed_when: pre_audit_summary.stderr | length > 0 - register: pre_audit_summary + - name: "Pre Audit | capture data {{ pre_audit_outfile }}" + ansible.builtin.shell: "tail -2 {{ pre_audit_outfile }}" + register: pre_audit + changed_when: false - - name: Pre Audit | Set Fact for audit summary - ansible.builtin.set_fact: - pre_audit_results: "{{ pre_audit_summary.stdout }}" - -- name: Audit_Only | Run Audit Only - when: audit_only - ansible.builtin.import_tasks: - file: audit_only.yml + - name: Pre Audit | Capture pre-audit result + ansible.builtin.set_fact: + pre_audit_summary: "{{ pre_audit.stdout_lines }}" + when: + - audit_format == "documentation" diff --git a/tasks/prelim.yml b/tasks/prelim.yml index 7c31c25..f555337 100644 --- a/tasks/prelim.yml +++ b/tasks/prelim.yml @@ -2,361 +2,262 @@ # Preliminary tasks that should always be run # List users in order to look files inside each home directory - -- name: "PRELIM | Include audit specific variables" - when: run_audit or audit_only or setup_audit - tags: - - setup_audit - - run_audit - ansible.builtin.include_vars: - file: audit.yml - -- name: "PRELIM | Include pre-remediation audit tasks" - when: run_audit or audit_only or setup_audit - tags: run_audit - ansible.builtin.import_tasks: pre_remediation_audit.yml - -- name: "PRELIM | AUDIT | Interactive Users" - tags: always - ansible.builtin.shell: > - grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false" && $7 != "/dev/null") { print $1":"$3":"$6 }' +- name: "PRELIM | List users accounts" + ansible.builtin.shell: "awk -F: '{print $1}' /etc/passwd" changed_when: false check_mode: false - register: prelim_interactive_users_raw + register: users + tags: + - level1-server + - level1-workstation + - users -- name: "PRELIM | AUDIT | Interactive Users (reformat)" - tags: always - ansible.builtin.set_fact: - prelim_interactive_users: "{{ prelim_interactive_users | default([]) + [dict([('username', item.split(':')[0]), ('uid', item.split(':')[1]), ('home', item.split(':')[2])])] }}" - loop: "{{ prelim_interactive_users_raw.stdout_lines }}" +- name: "PRELIM | capture /etc/password variables" + ansible.builtin.include_tasks: parse_etc_password.yml + tags: + - rule_5.5.2 + - rule_5.6.2 + - rule_6.2.9 + - rule_6.2.10 + - rule_6.2.11 + - rhel9cis_section5 + - rhel9cis_section6 + - level1-server -- name: "PRELIM | AUDIT | Interactive User accounts home directories" - tags: always - ansible.builtin.shell: > - grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false" && $7 != "/dev/null") { print $6 }' +- name: "PRELIM | Interactive User accounts" + ansible.builtin.shell: 'cat /etc/passwd | grep -Ev "nologin|/sbin" | cut -d: -f6' + changed_when: false + register: interactive_users_home + tags: + - always + +- name: "PRELIM | Gather accounts with empty password fields" + ansible.builtin.shell: "cat /etc/shadow | awk -F: '($2 == \"\" ) {j++;print $1; } END {exit j}'" changed_when: false check_mode: false - register: prelim_interactive_users_home - -- name: "PRELIM | AUDIT | Interactive UIDs" - tags: always - ansible.builtin.shell: > - grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false") { print $3 }' - changed_when: false - check_mode: false - register: prelim_interactive_uids - -- name: "PRELIM | AUDIT | Capture /etc/password variables" - tags: always - ansible.builtin.include_tasks: - file: parse_etc_password.yml - -- name: "PRELIM | PATCH | Ensure python3-libselinux is installed" - when: '"python3-libselinux" not in ansible_facts.packages' - ansible.builtin.package: - name: python3-libselinux - state: present - -- name: PRELIM | AUDIT | Section 1.1 | Create list of mount points - tags: always - ansible.builtin.set_fact: - prelim_mount_names: "{{ ansible_facts.mounts | map(attribute='mount') | list }}" - -- name: PRELIM | AUDIT | Section 1.1 | Retrieve mount options - tags: always - block: - - name: PRELIM | AUDIT | Section 1.1 | Retrieve mount options - call mount # noqa command-instead-of-module - ansible.builtin.shell: | - mount | awk '{print $1, $3, $5, $6}' - changed_when: false - check_mode: false - register: prelim_mount_output - - - name: PRELIM | AUDIT | Section 1.1 | Retrieve mount options - build fact # This is inherited and used in mountpoints tasks - ansible.builtin.set_fact: - prelim_mount_point_fs_and_options: >- - {%- set prelim_mount_point_fs_and_options = {} -%} - {%- for line in prelim_mount_output.stdout_lines -%} - {%- set fields = line.split() -%} - {%- set _ = prelim_mount_point_fs_and_options.update({fields[1]: {'src': fields[0], 'fs_type': fields[2], 'original_options': fields[3][1:-1].split(','), 'options': fields[3][1:-1].split(',')}}) -%} - {%- endfor -%} - {{ prelim_mount_point_fs_and_options }} - - - name: "PRELIM | AUDIT | Debug of mount variables to assist in troubleshooting" - when: rhel9cis_debug_mount_data - ansible.builtin.debug: - msg: "{{ prelim_mount_point_fs_and_options }}" - -- name: "PRELIM | PATCH | Update to latest gpg keys" - when: - - rhel9cis_rule_1_2_1_1 - - ansible_facts.distribution != 'RedHat' - - ansible_facts.distribution != 'OracleLinux' - ansible.builtin.package: - name: "{{ gpg_key_package }}" - state: latest - -- name: "PRELIM | AUDIT | Import gpg keys | RedHat Only" - when: - - rhel9cis_rule_1_2_1_1 - - rhel9cis_force_gpg_key_import - - ansible_facts.distribution == 'RedHat' - block: - - name: "PRELIM | AUDIT | Import gpg keys | get data" - ansible.builtin.command: rpm -q gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SUMMARY}\n' # noqa command-instead-of-module - changed_when: false - failed_when: false - check_mode: false - register: prelim_check_gpg_imported - - - name: "PRELIM | AUDIT | Import gpg keys | Check Package" # noqa command-instead-of-module - when: "'not installed' in prelim_check_gpg_imported.stdout" - ansible.builtin.shell: rpm -qi redhat-release | grep Signature # noqa command-instead-of-module - changed_when: false - failed_when: false - check_mode: false - register: prelim_os_gpg_package_valid - - - name: "PRELIM | PATCH | Force keys to be imported" # noqa command-instead-of-module - when: - - "'not installed' in prelim_check_gpg_imported.stdout" - - "'Key ID 199e2f91fd431d51' in prelim_os_gpg_package_valid.stdout" - ansible.builtin.rpm_key: - key: /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release - state: present - -- name: "PRELIM | AUDIT | Check systemd coredump" - when: rhel9cis_rule_1_5_4 + register: empty_password_accounts tags: - - level1-server - - level1-workstation - - rule_1.5.4 - - systemd - ansible.builtin.stat: - path: /etc/systemd/coredump.conf - register: prelim_systemd_coredump + - level1-server + - level1-workstation + - passwords -- name: "PRELIM | PATCH | Setup crypto-policy" - when: rhel9cis_crypto_policy_ansiblemanaged - tags: - - level1-server - - level1-workstation - - rule_1.6.1 - - crypto - block: - - name: "PRELIM | PATCH | Install crypto-policies | pkgs present" - ansible.builtin.package: - name: - - crypto-policies - - crypto-policies-scripts - state: present - - - name: "PRELIM | AUDIT | Gather system-wide crypto-policy" - ansible.builtin.command: 'update-crypto-policies --show' - changed_when: false - check_mode: false - register: prelim_system_wide_crypto_policy - - - name: "PRELIM | AUDIT | Gather system-wide crypto-policy | set fact system policy" - ansible.builtin.set_fact: - current_crypto_policy: "{{ prelim_system_wide_crypto_policy.stdout.split(':')[0] }}" - - - name: "PRELIM | AUDIT | Gather system-wide crypto-policy module | set fact system policy submodule" - when: "':' in prelim_system_wide_crypto_policy.stdout" - ansible.builtin.set_fact: - current_crypto_module: "{{ prelim_system_wide_crypto_policy.stdout.split(':')[1] }}" - -- name: "PRELIM | AUDIT | Set facts based on boot type" - tags: always - block: - - name: "PRELIM | AUDIT | Check whether machine is UEFI-based" - ansible.builtin.stat: - path: /sys/firmware/efi - register: prelim_efi_boot - - - name: "PRELIM | AUDIT | Set legacy boot and grub path | Bios" - when: not prelim_efi_boot.stat.exists - ansible.builtin.set_fact: - rhel9cis_legacy_boot: true - grub2_path: /etc/grub2.cfg - - - name: "PRELIM | AUDIT | Set grub fact | UEFI" - when: prelim_efi_boot.stat.exists - ansible.builtin.set_fact: - grub2_path: /etc/grub2-efi.cfg - -- name: "PRELIM | AUDIT | Discover Gnome Desktop Environment" - tags: always - ansible.builtin.stat: - path: /usr/share/gnome/gnome-version.xml - register: prelim_gnome_present - -- name: "PRELIM | PATCH | Install dconf if gui installed" - when: rhel9cis_gui - tags: always - ansible.builtin.package: - name: dconf - state: present - -- name: "PRELIM | AUDIT | Wireless adapter pre-requisites" - when: - - rhel9cis_rule_3_1_2 - - not system_is_container - tags: always - block: - - name: "PRELIM | AUDIT | Discover is wireless adapter on system" - ansible.builtin.command: find /sys/class/net/*/ -type d -name wireless - register: discover_wireless_adapters - changed_when: false - check_mode: false - failed_when: discover_wireless_adapters.rc not in [ 0, 1 ] - - - name: "PRELIM | PATCH | Install Network-Manager | if wireless adapter present" - when: - - discover_wireless_adapters.rc == 0 - - "'NetworkManager' not in ansible_facts.packages" - ansible.builtin.package: - name: NetworkManager - state: present - -- name: "PRELIM | PATCH | Install Cronie" - when: - - rhel9cis_rule_5_1_1 - - '"cronie" not in ansible_facts.packages' - tags: - - level1-server - - level1-workstation - - rule_5.1.1 - - cron - ansible.builtin.package: - name: cronie - state: present - -# Added to ensure ssh drop in file exists if not default /etc/ssh/sshd_config -- name: "PRELIM | PATCH | SSH Config file is not exist" - when: - - rhel9cis_sshd_config_file != '/etc/ssh/sshd_config' - - "'openssh-server' in ansible_facts.packages" - tags: - - always - - level1_server - - level1_workstation - ansible.builtin.file: - path: "{{ rhel9cis_sshd_config_file }}" - owner: root - group: root - mode: 'go-rwx' - state: touch - -- name: "PRELIM | PATCH | sshd_config.d/50-redhat.conf exists" - when: rhel9cis_rule_5_1_10 or rhel9cis_rule_5_1_11 - ansible.builtin.stat: - path: /etc/ssh/sshd_config.d/50-redhat.conf - register: prelim_sshd_50_redhat_file - -- name: "PRELIM | AUDIT | Capture pam security related files" - tags: always - ansible.builtin.find: - paths: - - /etc/security/pwquality.conf.d/ - patterns: '*.conf' - register: prelim_pam_pwquality_confs - -- name: "PRELIM | AUDIT | Gather UID 0 accounts other than root" - when: rhel9cis_rule_5_4_2_1 - tags: - - rule_5.4.2.1 - - level1-server - - level1-workstation - - users +- name: "PRELIM | Gather UID 0 accounts other than root" ansible.builtin.shell: "cat /etc/passwd | awk -F: '($3 == 0 && $1 != \"root\") {i++;print $1 } END {exit i}'" changed_when: false check_mode: false - register: prelim_uid_zero_accounts_except_root - -- name: "PRELIM | PATCH | Create journald config directory" - when: - - rhel9cis_syslog == 'journald' - - rhel9cis_rule_6_2_1_3 or - rhel9cis_rule_6_2_1_4 - tags: always - ansible.builtin.file: - path: /etc/systemd/journald.conf.d - state: directory - mode: 'u+x,g-w,o-rwx' - -- name: "PRELIM | PATCH | Configure System Accounting (auditd)" - when: - - '"auditd" not in ansible_facts.packages' - - rhel9cis_rule_6_3_1_1 + register: rhel9cis_uid_zero_accounts_except_root tags: - - level2-server - - level2-workstation - - patch - - rule_6.3.1.1 - - auditd - ansible.builtin.package: - name: audit - state: present - become: true + - rule_6.2.9 + - level1-server + - level1-workstation + - users -- name: "PRELIM | AUDIT | Discover audit logfile" - when: - - rhel9cis_rule_6_3_4_1 or - rhel9cis_rule_6_3_4_2 or - rhel9cis_rule_6_3_4_3 or - rhel9cis_rule_6_3_4_4 - tags: always - ansible.builtin.shell: grep ^log_file /etc/audit/auditd.conf | awk '{ print $NF }' - changed_when: false - check_mode: false - register: prelim_auditd_logfile - -- name: "PRELIM | AUDIT | Audit conf and rules files | list files" - when: - - rhel9cis_rule_6_3_4_5 or - rhel9cis_rule_6_3_4_6 or - rhel9cis_rule_6_3_4_7 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.4.5 - - rule_6.3.4.6 - - rule_6.3.4.7 - ansible.builtin.find: - path: /etc/audit - file_type: file - recurse: true - patterns: '*.conf,*.rules' - register: prelim_auditd_conf_files - -- name: "PRELIM | AUDIT | Discover Interactive UID_MIN and UID_MAX from /etc/login.defs" - when: rhel9cis_discover_int_uid - tags: always +- name: "PRELIM | Setup crypto-policy" block: - - name: "PRELIM | AUDIT | Capture UID_MIN from /etc/login.defs" - ansible.builtin.command: awk '/^UID_MIN/ {print $2}' /etc/login.defs - changed_when: false - failed_when: false - check_mode: false - register: prelim_uid_min_id + - name: "PRELIM | Install crypto-policies" + ansible.builtin.package: + name: + - crypto-policies + - crypto-policies-scripts + state: present - - name: "PRELIM | AUDIT | Capture UID_MAX from /etc/login.defs" - ansible.builtin.command: awk '/^UID_MAX/ {print $2}' /etc/login.defs - changed_when: false - failed_when: false - check_mode: false - register: prelim_uid_max_id + - name: "PRELIM | Gather system-wide crypto-policy" + ansible.builtin.shell: update-crypto-policies --show + changed_when: false + check_mode: false + register: system_wide_crypto_policy + when: + - rhel9cis_rule_1_10 + tags: + - level1-server + - level1-workstation + - rule_1.10 + - crypto -- name: "PRELIM | AUDIT | Set facts for interactive UID/GID ranges" - tags: always +- name: "PRELIM | if systemd coredump" + ansible.builtin.stat: + path: /etc/systemd/coredump.conf + register: systemd_coredump + when: + - rhel9cis_rule_1_5_1 + tags: + - level1-server + - level1-workstation + - rule_1.5.1 + - systemd + +- name: "PRELIM | Section 1.1 | Create list of mount points" ansible.builtin.set_fact: - prelim_min_int_uid: "{{ prelim_uid_min_id.stdout | default(min_int_uid) }}" - prelim_max_int_uid: "{{ prelim_uid_max_id.stdout | default(max_int_uid) }}" + mount_names: "{{ ansible_mounts | map(attribute='mount') | list }}" + tags: + - level1-server + - level1-workstation -- name: "PRELIM | AUDIT | Gather the package facts after prelim" - tags: always +- name: "PRELIM | Ensure python3-libselinux is installed" + ansible.builtin.package: + name: python3-libselinux + state: present + when: + - '"python3-libselinux" not in ansible_facts.packages' + +- name: "PRELIM | Set facts based on boot type" + block: + - name: "PRELIM | Check whether machine is UEFI-based" + ansible.builtin.stat: + path: /sys/firmware/efi + register: rhel_09_efi_boot + + - name: "PRELIM | set legacy boot and grub path | Bios" + ansible.builtin.set_fact: + rhel9cis_legacy_boot: true + grub2_path: /etc/grub2.cfg + when: not rhel_09_efi_boot.stat.exists + + - name: "PRELIM | set grub fact | UEFI" + ansible.builtin.set_fact: + grub2_path: /etc/grub2-efi.cfg + when: rhel_09_efi_boot.stat.exists + +- name: "PRELIM | Update to latest gpg keys" + ansible.builtin.package: + name: "{{ gpg_key_package }}" + state: latest + when: + - rhel9cis_rule_1_2_4 + - ansible_distribution != 'RedHat' + - ansible_distribution != 'OracleLinux' + +- name: "PRELIM | Section 4.1 | Configure System Accounting (auditd)" + ansible.builtin.package: + name: audit + state: present + become: true + when: + - '"auditd" not in ansible_facts.packages' + - rhel9cis_rule_4_1_1_1 + tags: + - level2-server + - level2-workstation + - patch + - rule_4.1.1.1 + - auditd + +- name: "PRELIM | 4.1.4.5 | Audit conf and rules files | list files" + ansible.builtin.find: + path: /etc/audit + file_type: file + recurse: true + patterns: '*.conf,*.rules' + register: auditd_conf_files + when: + - rhel9cis_rule_4_1_4_5 or + rhel9cis_rule_4_1_4_6 or + rhel9cis_rule_4_1_4_7 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.4.5 + - rule_4.1.4.6 + - rule_4.1.4.7 + +- name: "PRELIM | Section 5.1 | Configure cron" + ansible.builtin.package: + name: cronie + state: present + become: true + when: + - rhel9cis_rule_5_1_1 + - '"cronie" not in ansible_facts.packages' + tags: + - level1-server + - level1-workstation + - rule_5.1.1 + - cron + +# Added to ensure ssh drop in file exists if not default /etc/ssh/sshd_config +- name: "PRELIM | Section 5.2 | SSH" + ansible.builtin.file: + path: "{{ rhel9_cis_sshd_config_file }}" + owner: root + group: root + mode: 0600 + state: touch + when: + - rhel9_cis_sshd_config_file != '/etc/ssh/sshd_config' + - "'openssh-server' in ansible_facts.packages" + tags: + - ssh + - level1_server + - level1_workstation + +- name: "PRELIM | Install authconfig" + ansible.builtin.package: + name: authconfig + state: present + become: true + when: + - rhel9cis_use_authconfig + - rhel9cis_rule_5_3_1 or + rhel9cis_rule_5_3_2 or + rhel9cis_rule_5_3_3 or + '"authconfig" not in ansible_facts.packages or + "auditd-lib" not in ansible_facts.packages' + tags: + - level1-server + - level1-workstation + - rule_5.3.1 or + rule_5.3.2 or + rule_5.3.3 + - authconfig + - auditd + +- name: "PRELIM | 5.3.4 | Find all sudoers files." + ansible.builtin.shell: "find /etc/sudoers /etc/sudoers.d/ -type f ! -name '*~' ! -name '*.*'" + changed_when: false + failed_when: false + check_mode: false + register: rhel9cis_sudoers_files + when: + - rhel9cis_rule_5_3_4 or + rhel9cis_rule_5_3_5 + tags: + - rule_5.3.4 + - rule_5.3.5 + +- name: "PRELIM | Discover Interactive UID MIN and MIN from logins.def" + block: + - name: "PRELIM | Capture UID_MIN information from logins.def" + ansible.builtin.shell: grep -w "^UID_MIN" /etc/login.defs | awk '{print $NF}' + changed_when: false + register: uid_min_id + + - name: "PRELIM | Capture UID_MAX information from logins.def" + ansible.builtin.shell: grep -w "^UID_MAX" /etc/login.defs | awk '{print $NF}' + changed_when: false + register: uid_max_id + + - name: "PRELIM | Capture GID_MIN information from logins.def" + ansible.builtin.shell: grep -w "^GID_MIN" /etc/login.defs | awk '{print $NF}' + changed_when: false + register: gid_min_id + + - name: "PRELIM | set_facts for interactive uid/gid" + ansible.builtin.set_fact: + min_int_uid: "{{ uid_min_id.stdout }}" + max_int_uid: "{{ uid_max_id.stdout }}" + min_int_gid: "{{ gid_min_id.stdout }}" + +- name: "PRELIM | Output of uid findings" + ansible.builtin.debug: + msg: "{{ min_int_uid }} {{ max_int_uid }}" + + when: + - not discover_int_uid + +- name: "PRELIM | Gather the package facts after prelim" ansible.builtin.package_facts: - manager: auto + manager: auto + tags: + - always diff --git a/tasks/section_1/cis_1.1.1.x.yml b/tasks/section_1/cis_1.1.1.x.yml index adc094d..7a88f6f 100644 --- a/tasks/section_1/cis_1.1.1.x.yml +++ b/tasks/section_1/cis_1.1.1.x.yml @@ -1,292 +1,66 @@ --- -- name: "1.1.1.1 | PATCH | Ensure cramfs kernel module is not available" - when: rhel9cis_rule_1_1_1_1 - tags: - - level1-server - - level1-workstation - - patch - - rule_1.1.1.1 - - cramfs - - NIST800-53R5_CM-7 +- name: "1.1.1.1 | PATCH | Ensure mounting of squashfs filesystems is disabled" block: - - name: "1.1.1.1 | PATCH | Ensure cramfs kernel module is not available | Edit modprobe config" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/CIS.conf - regexp: "^(#)?install cramfs(\\s|$)" - line: "install cramfs /bin/true" - create: true - mode: 'go-rwx' + - name: "1.1.1.1 | PATCH | Ensure mounting of squashfs filesystems is disabled | Edit modprobe config" + ansible.builtin.lineinfile: + path: /etc/modprobe.d/CIS.conf + regexp: "^(#)?install squashfs(\\s|$)" + line: "install squashfs /bin/true" + create: true + mode: 0600 - - name: "1.1.1.1 | PATCH | Ensure cramfs kernel module is not available | blacklist" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/blacklist.conf - regexp: "^(#)?blacklist cramfs(\\s|$)" - line: "blacklist cramfs" - create: true - mode: 'go-rwx' + - name: "1.1.1.1 | PATCH | Ensure mounting of squashfs filesystems is disabled | blacklist" + ansible.builtin.lineinfile: + path: /etc/modprobe.d/blacklist.conf + regexp: "^(#)?blacklist squashfs(\\s|$)" + line: "blacklist squashfs" + create: true + mode: 0600 - - name: "1.1.1.1 | PATCH | Ensure cramfs kernel module is not available | Disable cramfs" - when: - - not system_is_container - community.general.modprobe: - name: cramfs - state: absent + - name: "1.1.1.1 | PATCH | Ensure mounting of squashfs filesystems is disabled | Disable squashfs" + community.general.modprobe: + name: squashfs + state: absent + when: not system_is_container -- name: "1.1.1.2 | PATCH | Ensure freevxfs kernel module is not available" - when: rhel9cis_rule_1_1_1_2 + when: + - rhel9cis_rule_1_1_1_1 tags: - - level1-server - - level1-workstation - - patch - - rule_1.1.1.2 - - freevxfs - - NIST800-53R5_CM-7 + - level2-server + - level2-workstation + - patch + - rule_1.1.1.1 + - squashfs + +- name: "1.1.1.2 | PATCH | Ensure mounting of udf filesystems is disabled" block: - - name: "1.1.1.2 | PATCH | Ensure freevxfs kernel module is not available | Edit modprobe config" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/CIS.conf - regexp: "^(#)?install freevxfs(\\s|$)" - line: "install freevxfs /bin/true" - create: true - mode: 'go-rwx' + - name: "1.1.1.2 | PATCH | Ensure mounting of udf filesystems is disable | Edit modprobe config" + ansible.builtin.lineinfile: + path: /etc/modprobe.d/CIS.conf + regexp: "^(#)?install udf(\\s|$)" + line: "install udf /bin/true" + create: true + mode: 0600 - - name: "1.1.1.2 | PATCH | Ensure freevxfs kernel module is not available | blacklist" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/blacklist.conf - regexp: "^(#)?blacklist freevxfs(\\s|$)" - line: "blacklist freevxfs" - create: true - mode: 'go-rwx' + - name: "1.1.1.2 | PATCH | Ensure mounting of udf filesystems is disabled | blacklist" + ansible.builtin.lineinfile: + path: /etc/modprobe.d/blacklist.conf + regexp: "^(#)?blacklist udf(\\s|$)" + line: "blacklist udf" + create: true + mode: 0600 - - name: "1.1.1.2 | PATCH | Ensure freevxfs kernel module is not available | Disable freevxfs" - when: not system_is_container - community.general.modprobe: - name: freevxfs - state: absent - -- name: "1.1.1.3 | PATCH | Ensure hfs kernel module is not available" - when: rhel9cis_rule_1_1_1_3 + - name: "1.1.1.2 | PATCH | Ensure mounting of udf filesystems is disable | Disable udf" + community.general.modprobe: + name: udf + state: absent + when: not system_is_container + when: + - rhel9cis_rule_1_1_1_2 tags: - - level1-server - - level1-workstation - - patch - - rule_1.1.1.3 - - hfs - - NIST800-53R5_CM-7 - block: - - name: "1.1.1.3 | PATCH | Ensure hfs kernel module is not available | Edit modprobe config" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/CIS.conf - regexp: "^(#)?install hfs(\\s|$)" - line: "install hfs /bin/true" - create: true - mode: 'go-rwx' - - - name: "1.1.1.3 | PATCH | Ensure hfs kernel module is not available | blacklist" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/blacklist.conf - regexp: "^(#)?blacklist hfs(\\s|$)" - line: "blacklist hfs" - create: true - mode: 'go-rwx' - - - name: "1.1.1.3 | PATCH | Ensure hfs kernel module is not available | Disable hfs" - when: not system_is_container - community.general.modprobe: - name: hfs - state: absent - -- name: "1.1.1.4 | PATCH | Ensure hfsplus kernel module is not available" - when: rhel9cis_rule_1_1_1_4 - tags: - - level1-server - - level1-workstation - - patch - - rule_1.1.1.4 - - hfsplus - - NIST800-53R5_CM-7 - block: - - name: "1.1.1.4 | PATCH | Ensure hfsplus kernel module is not available | Edit modprobe config" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/CIS.conf - regexp: "^(#)?install hfsplus(\\s|$)" - line: "install hfsplus /bin/true" - create: true - mode: 'go-rwx' - - - name: "1.1.1.4 | PATCH | Ensure hfsplus kernel module is not available | blacklist" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/blacklist.conf - regexp: "^(#)?blacklist hfsplus(\\s|$)" - line: "blacklist hfsplus" - create: true - mode: 'go-rwx' - - - name: "1.1.1.4 | PATCH | Ensure hfsplus kernel module is not available | Disable hfsplus" - when: not system_is_container - community.general.modprobe: - name: hfsplus - state: absent - -- name: "1.1.1.5 | PATCH | Ensure jffs2 kernel module is not available" - when: rhel9cis_rule_1_1_1_5 - tags: - - level1-server - - level1-workstation - - patch - - rule_1.1.1.5 - - jffs2 - - NIST800-53R5_CM-7 - block: - - name: "1.1.1.5 | PATCH | Ensure jffs2 kernel module is not available | Edit modprobe config" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/CIS.conf - regexp: "^(#)?install jffs2(\\s|$)" - line: "install jffs2 /bin/true" - create: true - mode: 'go-rwx' - - - name: "1.1.1.5 | PATCH | Ensure jffs2 kernel module is not available | blacklist" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/blacklist.conf - regexp: "^(#)?blacklist jffs2(\\s|$)" - line: "blacklist jffs2" - create: true - mode: 'go-rwx' - - - name: "1.1.1.5 | PATCH | Ensure jffs2 kernel module is not available | Disable jffs2" - when: not system_is_container - community.general.modprobe: - name: jffs2 - state: absent - -- name: "1.1.1.6 | PATCH | Ensure squashfs kernel module is not available" - when: rhel9cis_rule_1_1_1_6 - tags: - - level2-server - - level2-workstation - - patch - - rule_1.1.1.6 - - squashfs - - NIST800-53R5_CM-7 - block: - - name: "1.1.1.6 | PATCH | Ensure squashfs kernel module is not available | Edit modprobe config" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/CIS.conf - regexp: "^(#)?install squashfs(\\s|$)" - line: "install squashfs /bin/true" - create: true - mode: 'go-rwx' - - - name: "1.1.1.6 | PATCH | Ensure squashfs kernel module is not available | blacklist" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/blacklist.conf - regexp: "^(#)?blacklist squashfs(\\s|$)" - line: "blacklist squashfs" - create: true - mode: 'go-rwx' - - - name: "1.1.1.6 | PATCH | Ensure squashfs kernel module is not available | Disable squashfs" - when: not system_is_container - community.general.modprobe: - name: squashfs - state: absent - -- name: "1.1.1.7 | PATCH | Ensure udf kernel module is not available" - when: rhel9cis_rule_1_1_1_7 - tags: - - level2-server - - level2-workstation - - patch - - rule_1.1.1.7 - - udf - - NIST800-53R5_CM-7 - block: - - name: "1.1.1.7 | PATCH | Ensure udf kernel module is not available | Edit modprobe config" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/CIS.conf - regexp: "^(#)?install udf(\\s|$)" - line: "install udf /bin/true" - create: true - mode: 'go-rwx' - - - name: "1.1.1.7 | PATCH | Ensure udf kernel module is not available | blacklist" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/blacklist.conf - regexp: "^(#)?blacklist udf(\\s|$)" - line: "blacklist udf" - create: true - mode: 'go-rwx' - - - name: "1.1.1.7 | PATCH | Ensure udf kernel module is not available | Disable udf" - when: not system_is_container - community.general.modprobe: - name: udf - state: absent - -- name: "1.1.1.8 | PATCH | Ensure usb-storage kernel module is not available" - when: rhel9cis_rule_1_1_1_8 - tags: - - level1-server - - level2-workstation - - patch - - rule_1.1.1.8 - - usb - - NIST800-53R5_SI-3 - block: - - name: "1.1.1.8 | PATCH | Ensure usb-storage kernel module is not available | Edit modprobe config" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/CIS.conf - regexp: "^(#)?install usb-storage(\\s|$)" - line: "install usb-storage /bin/true" - create: true - mode: 'go-rwx' - - - name: "1.1.1.8 | PATCH | Ensure usb-storage kernel module is not available | blacklist" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/blacklist.conf - regexp: "^(#)?blacklist usb-storage(\\s|$)" - line: "blacklist usb-storage" - create: true - mode: 'go-rwx' - - - name: "1.1.1.8 | PATCH | Ensure usb-storage kernel module is not available | Disable usb" - when: not system_is_container - community.general.modprobe: - name: usb-storage - state: absent - -- name: "1.1.1.9 | PATCH | Ensure unused filesystems kernel modules are not available" - when: rhel9cis_rule_1_1_1_9 - tags: - - level1-server - - level1-workstation - - patch - - rule_1.1.1.9 - vars: - warn_control_id: '1.1.1.9' - block: - - name: "1.1.1.9 | PATCH | Ensure unused filesystems kernel modules are not available | Add discovery script" - ansible.builtin.copy: - src: fs_with_cves.sh - dest: /var/fs_with_cves.sh - owner: root - group: root - mode: 'u+x,go-wx' - - - name: "1.1.1.9 | AUDIT | Ensure unused filesystems kernel modules are not available | Run discovery script" - ansible.builtin.command: /var/fs_with_cves.sh - changed_when: false - failed_when: discovered_fs_modules_loaded.rc not in [ 0, 99 ] - register: discovered_fs_modules_loaded - - - name: "1.1.1.9 | AUDIT | Ensure unused filesystems kernel modules are not available | Output Warning" - when: discovered_fs_modules_loaded.stdout | length > 0 - ansible.builtin.debug: - msg: "{{ ['Warning!! Discovered loaded Filesystem modules that need attention. This is a manual task'] + discovered_fs_modules_loaded.stdout_lines }}" - - - name: "1.1.1.9 | AUDIT | Ensure unused filesystems kernel modules are not available | Capture Warning" - when: discovered_fs_modules_loaded.stdout | length > 0 - ansible.builtin.import_tasks: - file: warning_facts.yml + - level2-server + - level2-workstation + - patch + - rule_1.1.1.2 + - udf diff --git a/tasks/section_1/cis_1.1.2.1.x.yml b/tasks/section_1/cis_1.1.2.1.x.yml deleted file mode 100644 index 9cca1ec..0000000 --- a/tasks/section_1/cis_1.1.2.1.x.yml +++ /dev/null @@ -1,132 +0,0 @@ ---- - -- name: "1.1.2.1.1 | PATCH | Ensure /tmp is a separate partition" - when: - - required_mount not in prelim_mount_names - - rhel9cis_rule_1_1_2_1_1 - tags: - - level1-server - - level1-workstation - - audit - - mounts - - rule_1.1.2.1.1 - - NIST800-53R5_CM-7 - vars: - warn_control_id: "1.1.2.1.1" - required_mount: "/tmp" - block: - - name: "1.1.2.1.1 | AUDIT | Ensure /tmp is a separate partition | check for mount" - ansible.builtin.command: findmnt -kn "{{ required_mount }}" - changed_when: false - failed_when: discovered_tmp_mount.rc not in [ 0, 1 ] - register: discovered_tmp_mount - - - name: "1.1.2.1.1 | AUDIT | Ensure /tmp is a separate partition | Absent" - when: discovered_tmp_mount is undefined - ansible.builtin.debug: - msg: "Warning!! {{ required_mount }} is not mounted on a separate partition" - - - name: "1.1.2.1.1 | AUDIT | Ensure /tmp is a separate partition | Present" - when: discovered_tmp_mount is undefined - ansible.builtin.import_tasks: - file: warning_facts.yml - -# via fstab -- name: "1.1.2.1.2 | PATCH | Ensure nodev option set on /tmp partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - not prelim_mount_point_fs_and_options[mount_point]['src'] == "tmpfs" - - rhel9cis_rule_1_1_2_1_2 - - not rhel9cis_tmp_svc - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.1.2 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/tmp" - required_option: nodev - notify: &mount_option_notify - - "Remount {{ mount_point }}" - ansible.builtin.set_fact: &mount_option_set_fact - prelim_mount_point_fs_and_options: | - {{ prelim_mount_point_fs_and_options | combine({mount_point: {'options': (prelim_mount_point_fs_and_options[mount_point]['options'] + [required_option])}}, recursive=True) }} - changed_when: &mount_option_changed_when - - required_option not in prelim_mount_point_fs_and_options[mount_point]['original_options'] - -- name: "1.1.2.1.3 | PATCH | Ensure nosuid option set on /tmp partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - not prelim_mount_point_fs_and_options[mount_point]['src'] == "tmpfs" - - rhel9cis_rule_1_1_2_1_3 - - not rhel9cis_tmp_svc - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.1.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/tmp" - required_option: nosuid - notify: *mount_option_notify - ansible.builtin.set_fact: - <<: *mount_option_set_fact - changed_when: *mount_option_changed_when - -- name: "1.1.2.1.4 | PATCH | Ensure noexec option set on /tmp partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - not prelim_mount_point_fs_and_options[mount_point]['src'] == "tmpfs" - - rhel9cis_rule_1_1_2_1_4 - - not rhel9cis_tmp_svc - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.1.4 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/tmp" - required_option: noexec - notify: *mount_option_notify - ansible.builtin.set_fact: - <<: *mount_option_set_fact - changed_when: *mount_option_changed_when - -# via systemd -- name: | - "1.1.2.1.1 | PATCH | Ensure /tmp is configured - 1.1.2.1.2 | PATCH | Ensure nodev option set on /tmp partition - 1.1.2.1.3 | PATCH | Ensure noexec option set on /tmp partition - 1.1.2.1.4 | PATCH | Ensure nosuid option set on /tmp partition" - when: - - rhel9cis_tmp_svc - - rhel9cis_rule_1_1_2_1_1 or rhel9cis_rule_1_1_2_1_2 or rhel9cis_rule_1_1_2_1_3 or rhel9cis_rule_1_1_2_1_4 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.1.1 - - rule_1.1.2.1.2 - - rule_1.1.2.1.3 - - rule_1.1.2.1.4 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/tmp" - ansible.builtin.template: - src: etc/systemd/system/tmp.mount.j2 - dest: /etc/systemd/system/tmp.mount - owner: root - group: root - mode: 'go-wx' - notify: *mount_option_notify diff --git a/tasks/section_1/cis_1.1.2.2.x.yml b/tasks/section_1/cis_1.1.2.2.x.yml deleted file mode 100644 index 57e92eb..0000000 --- a/tasks/section_1/cis_1.1.2.2.x.yml +++ /dev/null @@ -1,95 +0,0 @@ ---- - -- name: "1.1.2.2.1 | PATCH | Ensure /dev/shm is a separate partition" - when: - - rhel9cis_rule_1_1_2_2_1 - - required_mount not in prelim_mount_names - tags: - - level1-server - - level1-workstation - - audit - - mounts - - rule_1.1.2.2.1 - - NIST800-53R5_CM-7 - vars: - warn_control_id: "1.1.2.2.1" - required_mount: "/dev/shm" - block: - - name: "1.1.2.2.1 | AUDIT | Ensure /dev/shm is a separate partition | check for mount" - ansible.builtin.command: findmnt -kn "{{ required_mount }}" - changed_when: false - failed_when: discovered_dev_shm_mount.rc not in [ 0, 1 ] - register: discovered_dev_shm_mount - - - name: "1.1.2.2.1 | AUDIT | Ensure /dev/shm is a separate partition | Absent" - when: discovered_dev_shm_mount is undefined - ansible.builtin.debug: - msg: "Warning!! {{ required_mount }} is not mounted on a separate partition" - - - name: "1.1.2.2.1 | AUDIT | Ensure /dev/shm is a separate partition | Present" - when: discovered_dev_shm_mount is undefined - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "1.1.2.2.2 | PATCH | Ensure nodev option set on /dev/shm partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_2_2 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.2.2 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/dev/shm" - required_option: nodev - notify: &mount_option_notify - - "Remount {{ mount_point }}" - ansible.builtin.set_fact: &mount_option_set_fact - prelim_mount_point_fs_and_options: | - {{ prelim_mount_point_fs_and_options | combine({mount_point: {'options': (prelim_mount_point_fs_and_options[mount_point]['options'] + [required_option])}}, recursive=True) }} - changed_when: &mount_option_changed_when - - required_option not in prelim_mount_point_fs_and_options[mount_point]['original_options'] - -- name: "1.1.2.2.3 | PATCH | Ensure nosuid option set on /dev/shm partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_2_3 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.2.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/dev/shm" - required_option: nosuid - notify: *mount_option_notify - ansible.builtin.set_fact: - <<: *mount_option_set_fact - changed_when: *mount_option_changed_when - -- name: "1.1.2.2.4 | PATCH | Ensure noexec option set on /dev/shm partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_2_4 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.2.4 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/dev/shm" - required_option: noexec - notify: *mount_option_notify - ansible.builtin.set_fact: - <<: *mount_option_set_fact - changed_when: *mount_option_changed_when diff --git a/tasks/section_1/cis_1.1.2.3.x.yml b/tasks/section_1/cis_1.1.2.3.x.yml deleted file mode 100644 index 635648d..0000000 --- a/tasks/section_1/cis_1.1.2.3.x.yml +++ /dev/null @@ -1,74 +0,0 @@ ---- -- name: "1.1.2.3.1 | PATCH | Ensure /home is a separate partition" - when: - - rhel9cis_rule_1_1_2_3_1 - - required_mount not in prelim_mount_names - tags: - - level1-server - - level1-workstation - - audit - - mounts - - rule_1.1.2.3.1 - - NIST800-53R5_CM-7 - vars: - warn_control_id: "1.1.2.3.1" - required_mount: "/home" - block: - - name: "1.1.2.3.1 | AUDIT | Ensure /home is a separate partition | check for mount" - ansible.builtin.command: findmnt -kn "{{ required_mount }}" - changed_when: false - failed_when: discovered_home_mount.rc not in [ 0, 1 ] - register: discovered_home_mount - - - name: "1.1.2.3.1 | AUDIT | Ensure /home is a separate partition | Absent" - when: discovered_home_mount is undefined - ansible.builtin.debug: - msg: "Warning!! {{ required_mount }} is not mounted on a separate partition" - - - name: "1.1.2.3.1 | AUDIT | Ensure /home is a separate partition | Present" - when: discovered_home_mount is undefined - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "1.1.2.3.2 | PATCH | Ensure nodev option set on /home partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_3_2 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.3.2 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/home" - required_option: nodev - notify: &mount_option_notify - - "Remount {{ mount_point }}" - ansible.builtin.set_fact: &mount_option_set_fact - prelim_mount_point_fs_and_options: | - {{ prelim_mount_point_fs_and_options | combine({mount_point: {'options': (prelim_mount_point_fs_and_options[mount_point]['options'] + [required_option])}}, recursive=True) }} - changed_when: &mount_option_changed_when - - required_option not in prelim_mount_point_fs_and_options[mount_point]['original_options'] - -- name: "1.1.2.3.3 | PATCH | Ensure nosuid option set on /home partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_3_3 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.3.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/home" - required_option: nosuid - notify: *mount_option_notify - ansible.builtin.set_fact: - <<: *mount_option_set_fact - changed_when: *mount_option_changed_when diff --git a/tasks/section_1/cis_1.1.2.4.x.yml b/tasks/section_1/cis_1.1.2.4.x.yml deleted file mode 100644 index f89fe3f..0000000 --- a/tasks/section_1/cis_1.1.2.4.x.yml +++ /dev/null @@ -1,75 +0,0 @@ ---- - -- name: "1.1.2.4.1 | PATCH | Ensure /var is a separate partition" - when: - - rhel9cis_rule_1_1_2_4_1 - - required_mount not in prelim_mount_names - tags: - - level1-server - - level1-workstation - - audit - - mounts - - rule_1.1.2.4.1 - - NIST800-53R5_CM-7 - vars: - warn_control_id: '1.1.2.4.1' - required_mount: '/var' - block: - - name: "1.1.2.4.1 | AUDIT | Ensure /var is a separate partition | check for mount" - ansible.builtin.command: findmnt -kn "{{ required_mount }}" - changed_when: false - failed_when: discovered_var_mount.rc not in [ 0, 1 ] - register: discovered_var_mount - - - name: "1.1.2.4.1 | AUDIT | Ensure /var is a separate partition | Absent" - when: discovered_var_mount is undefined - ansible.builtin.debug: - msg: "Warning!! {{ required_mount }} is not mounted on a separate partition" - - - name: "1.1.2.4.1 | AUDIT | Ensure /var is a separate partition | Present" - when: discovered_var_mount is undefined - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "1.1.2.4.2 | PATCH | Ensure nodev option set on /var partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_4_2 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.4.2 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/var" - required_option: nodev - notify: &mount_option_notify - - "Remount {{ mount_point }}" - ansible.builtin.set_fact: &mount_option_set_fact - prelim_mount_point_fs_and_options: | - {{ prelim_mount_point_fs_and_options | combine({mount_point: {'options': (prelim_mount_point_fs_and_options[mount_point]['options'] + [required_option])}}, recursive=True) }} - changed_when: &mount_option_changed_when - - required_option not in prelim_mount_point_fs_and_options[mount_point]['original_options'] - -- name: "1.1.2.4.3 | PATCH | Ensure nosuid option set on /var partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_4_3 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.4.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/var" - required_option: nosuid - notify: *mount_option_notify - ansible.builtin.set_fact: - <<: *mount_option_set_fact - changed_when: *mount_option_changed_when diff --git a/tasks/section_1/cis_1.1.2.5.x.yml b/tasks/section_1/cis_1.1.2.5.x.yml deleted file mode 100644 index 180d016..0000000 --- a/tasks/section_1/cis_1.1.2.5.x.yml +++ /dev/null @@ -1,95 +0,0 @@ ---- - -- name: "1.1.2.5.1 | PATCH | Ensure /var/tmp is a separate partition" - when: - - rhel9cis_rule_1_1_2_5_1 - - required_mount not in prelim_mount_names - tags: - - level1-server - - level1-workstation - - audit - - mounts - - rule_1.1.2.5.1 - - NIST800-53R5_CM-7 - vars: - warn_control_id: '1.1.2.5.1' - required_mount: '/var/tmp' - block: - - name: "1.1.2.5.1 | AUDIT | Ensure /var/tmp is a separate partition | check for mount" - ansible.builtin.command: findmnt -kn "{{ required_mount }}" - changed_when: false - failed_when: discovered_var_tmp_mount.rc not in [ 0, 1 ] - register: discovered_var_tmp_mount - - - name: "1.1.2.5.1 | AUDIT | Ensure /var/tmp is a separate partition | Absent" - when: discovered_var_tmp_mount is undefined - ansible.builtin.debug: - msg: "Warning!! {{ required_mount }} is not mounted on a separate partition" - - - name: "1.1.2.5.1 | AUDIT | Ensure /var/tmp is a separate partition | Present" - when: discovered_var_tmp_mount is undefined - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "1.1.2.5.2 | PATCH | Ensure nodev option set on /var/tmp partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_5_2 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.5.2 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/var/tmp" - required_option: nodev - notify: &mount_option_notify - - "Remount {{ mount_point }}" - ansible.builtin.set_fact: &mount_option_set_fact - prelim_mount_point_fs_and_options: | - {{ prelim_mount_point_fs_and_options | combine({mount_point: {'options': (prelim_mount_point_fs_and_options[mount_point]['options'] + [required_option])}}, recursive=True) }} - changed_when: &mount_option_changed_when - - required_option not in prelim_mount_point_fs_and_options[mount_point]['original_options'] - -- name: "1.1.2.5.3 | PATCH | Ensure nosuid option set on /var/tmp partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_5_3 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.5.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/var/tmp" - required_option: nosuid - notify: *mount_option_notify - ansible.builtin.set_fact: - <<: *mount_option_set_fact - changed_when: *mount_option_changed_when - -- name: "1.1.2.5.4 | PATCH | Ensure noexec option set on /var/tmp partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_5_4 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.5.4 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/var/tmp" - required_option: noexec - notify: *mount_option_notify - ansible.builtin.set_fact: - <<: *mount_option_set_fact - changed_when: *mount_option_changed_when diff --git a/tasks/section_1/cis_1.1.2.6.x.yml b/tasks/section_1/cis_1.1.2.6.x.yml deleted file mode 100644 index b27e4cc..0000000 --- a/tasks/section_1/cis_1.1.2.6.x.yml +++ /dev/null @@ -1,95 +0,0 @@ ---- - -- name: "1.1.2.6.1 | PATCH | Ensure /var/log is a separate partition" - when: - - rhel9cis_rule_1_1_2_6_1 - - required_mount not in prelim_mount_names - tags: - - level1-server - - level1-workstation - - audit - - mounts - - rule_1.1.2.6.1 - - NIST800-53R5_CM-7 - vars: - warn_control_id: '1.1.2.6.1' - required_mount: '/var/log' - block: - - name: "1.1.2.6.1 | AUDIT | Ensure /var/log is a separate partition | check for mount" - ansible.builtin.command: findmnt -kn "{{ required_mount }}" - changed_when: false - failed_when: discovered_var_log_mount.rc not in [ 0, 1 ] - register: discovered_var_log_mount - - - name: "1.1.2.6.1 | AUDIT | Ensure /var/log is a separate partition | Absent" - when: discovered_var_log_mount is undefined - ansible.builtin.debug: - msg: "Warning!! {{ required_mount }} is not mounted on a separate partition" - - - name: "1.1.2.6.1 | AUDIT | Ensure /var/log is a separate partition | Present" - when: discovered_var_log_mount is undefined - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "1.1.2.6.2 | PATCH | Ensure nodev option set on /var/log partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_6_2 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.6.2 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/var/log" - required_option: nodev - notify: &mount_option_notify - - "Remount {{ mount_point }}" - ansible.builtin.set_fact: &mount_option_set_fact - prelim_mount_point_fs_and_options: | - {{ prelim_mount_point_fs_and_options | combine({mount_point: {'options': (prelim_mount_point_fs_and_options[mount_point]['options'] + [required_option])}}, recursive=True) }} - changed_when: &mount_option_changed_when - - required_option not in prelim_mount_point_fs_and_options[mount_point]['original_options'] - -- name: "1.1.2.6.3 | PATCH | Ensure nosuid option set on /var/log partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_6_3 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.6.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/var/log" - required_option: nosuid - notify: *mount_option_notify - ansible.builtin.set_fact: - <<: *mount_option_set_fact - changed_when: *mount_option_changed_when - -- name: "1.1.2.6.4 | PATCH | Ensure noexec option set on /var/log partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_6_4 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.6.4 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/var/log" - required_option: noexec - notify: *mount_option_notify - ansible.builtin.set_fact: - <<: *mount_option_set_fact - changed_when: *mount_option_changed_when diff --git a/tasks/section_1/cis_1.1.2.7.x.yml b/tasks/section_1/cis_1.1.2.7.x.yml deleted file mode 100644 index b4513dd..0000000 --- a/tasks/section_1/cis_1.1.2.7.x.yml +++ /dev/null @@ -1,95 +0,0 @@ ---- - -- name: "1.1.2.7.1 | PATCH | Ensure /var/log/audit is a separate partition" - when: - - rhel9cis_rule_1_1_2_7_1 - - required_mount not in prelim_mount_names - tags: - - level1-server - - level1-workstation - - audit - - mounts - - rule_1.1.2.7.1 - - NIST800-53R5_CM-7 - vars: - warn_control_id: '1.1.2.7.1' - required_mount: '/var/log/audit' - block: - - name: "1.1.2.7.1 | AUDIT | Ensure /var/log/audit is a separate partition | check for mount" - ansible.builtin.command: findmnt -kn "{{ required_mount }}" - changed_when: false - failed_when: discovered_var_log_audit_mount.rc not in [ 0, 1 ] - register: discovered_var_log_audit_mount - - - name: "1.1.2.7.1 | AUDIT | Ensure /var/log/audit is a separate partition | Absent" - when: discovered_var_log_audit_mount is undefined - ansible.builtin.debug: - msg: "Warning!! {{ required_mount }} is not mounted on a separate partition" - - - name: "1.1.2.7.1 | AUDIT | Ensure /var/log/audit is a separate partition | Present" - when: discovered_var_log_audit_mount is undefined - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "1.1.2.7.2 | PATCH | Ensure nodev option set on /var/log/audit partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_7_2 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.7.2 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/var/log/audit" - required_option: nodev - notify: &mount_option_notify - - "Remount {{ mount_point }}" - ansible.builtin.set_fact: &mount_option_set_fact - prelim_mount_point_fs_and_options: | - {{ prelim_mount_point_fs_and_options | combine({mount_point: {'options': (prelim_mount_point_fs_and_options[mount_point]['options'] + [required_option])}}, recursive=True) }} - changed_when: &mount_option_changed_when - - required_option not in prelim_mount_point_fs_and_options[mount_point]['original_options'] - -- name: "1.1.2.7.3 | PATCH | Ensure nosuid option set on /var/log/audit partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_7_3 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.7.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/var/log/audit" - required_option: nosuid - notify: *mount_option_notify - ansible.builtin.set_fact: - <<: *mount_option_set_fact - changed_when: *mount_option_changed_when - -- name: "1.1.2.7.4 | PATCH | Ensure noexec option set on /var/log/audit partition" - when: - - prelim_mount_point_fs_and_options[mount_point] is defined - - rhel9cis_rule_1_1_2_7_4 - tags: - - level1-server - - level1-workstation - - patch - - mounts - - rule_1.1.2.7.4 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - mount_point: "/var/log/audit" - required_option: noexec - notify: *mount_option_notify - ansible.builtin.set_fact: - <<: *mount_option_set_fact - changed_when: *mount_option_changed_when diff --git a/tasks/section_1/cis_1.1.2.x.yml b/tasks/section_1/cis_1.1.2.x.yml new file mode 100644 index 0000000..b4e1888 --- /dev/null +++ b/tasks/section_1/cis_1.1.2.x.yml @@ -0,0 +1,81 @@ +--- + +- name: "1.1.2.1 | PATCH | Ensure /tmp is a separate partition" + block: + - name: "1.1.2.1 | PATCH | Ensure /tmp is a separate partition | Absent" + ansible.builtin.debug: + msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" + + - name: "1.1.2.1 | PATCH | Ensure /tmp is a separate partition | Present" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '1.1.2.1' + required_mount: '/tmp' + when: + - required_mount not in mount_names + - rhel9cis_rule_1_1_2_1 + tags: + - level1-server + - level1-workstation + - audit + - mounts + - rule_1.1.2.1 + +# via fstab +- name: | + "1.1.2.2 | PATCH | Ensure nodev option set on /tmp partition" + "1.1.2.3 | PATCH | Ensure noexec option set on /tmp partition" + "1.1.2.4 | PATCH | Ensure nosuid option set on /tmp partition" + ansible.builtin.mount: + name: /tmp + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + state: present + opts: defaults,{% if rhel9cis_rule_1_1_2_2 %}nodev,{% endif %}{% if rhel9cis_rule_1_1_2_3 %}noexec,{% endif %}{% if rhel9cis_rule_1_1_2_4 %}nosuid{% endif %} + notify: Remount tmp + loop: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.device }}" + when: + - item.mount == "/tmp" + - not rhel9cis_tmp_svc + - rhel9cis_rule_1_1_2_2 or + rhel9cis_rule_1_1_2_3 or + rhel9cis_rule_1_1_2_4 + tags: + - level1-server + - level1-workstation + - patch + - mounts + - rule_1.1.2.2 + - rule_1.1.2.3 + - rule_1.1.2.4 + +# via systemd +- name: | + "1.1.2.1 | PATCH | Ensure /tmp is configured" + "1.1.2.2 | PATCH | Ensure nodev option set on /tmp partition" + "1.1.2.3 | PATCH | Ensure noexec option set on /tmp partition" + "1.1.2.4 | PATCH | Ensure nosuid option set on /tmp partition" + ansible.builtin.template: + src: etc/systemd/system/tmp.mount.j2 + dest: /etc/systemd/system/tmp.mount + owner: root + group: root + mode: 0644 + notify: Systemd restart tmp.mount + when: + - rhel9cis_tmp_svc + - rhel9cis_rule_1_1_2_1 or + rhel9cis_rule_1_1_2_2 or + rhel9cis_rule_1_1_2_3 or + rhel9cis_rule_1_1_2_4 + tags: + - level1-server + - level1-workstation + - patch + - mounts + - rule_1.1.2.1 + - rule_1.1.2.2 + - rule_1.1.2.3 + - rule_1.1.2.4 diff --git a/tasks/section_1/cis_1.1.3.x.yml b/tasks/section_1/cis_1.1.3.x.yml new file mode 100644 index 0000000..d873c51 --- /dev/null +++ b/tasks/section_1/cis_1.1.3.x.yml @@ -0,0 +1,49 @@ +--- + +- name: "1.1.3.1 | AUDIT | Ensure separate partition exists for /var" + block: + - name: "1.1.3.1 | AUDIT | Ensure separate partition exists for /var | Absent" + ansible.builtin.debug: + msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" + + - name: "1.1.3.1 | AUDIT | Ensure separate partition exists for /var | Present" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '1.1.3.1' + required_mount: '/var' + when: + - required_mount not in mount_names + - rhel9cis_rule_1_1_3_1 + tags: + - level2-server + - level2-workstation + - patch + - mounts + - rule_1.1.3.1 + +# skips if mount is absent +- name: | + "1.1.3.2 | PATCH | Ensure nodev option set on /var partition" + "1.1.3.3 | PATCH | Ensure nosuid option set on /var partition" + ansible.builtin.mount: + name: /var + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + state: present + opts: defaults,{% if rhel9cis_rule_1_1_3_2 %}nodev,{% endif %}{% if rhel9cis_rule_1_1_3_3 %}nosuid,{% endif %} + loop: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.device }}" + notify: Change_requires_reboot + when: + - item.mount == "/var" + - rhel9cis_rule_1_1_3_2 or + rhel9cis_rule_1_1_3_3 + tags: + - level1-server + - level1-workstation + - patch + - mounts + - skip_ansible_lint + - rule_1.1.3.2 + - rule_1.1.3.3 diff --git a/tasks/section_1/cis_1.1.4.x.yml b/tasks/section_1/cis_1.1.4.x.yml new file mode 100644 index 0000000..f063fbd --- /dev/null +++ b/tasks/section_1/cis_1.1.4.x.yml @@ -0,0 +1,53 @@ +--- + +# Skips if mount is absent +- name: "1.1.4.1 | AUDIT | Ensure separate partition exists for /var/tmp" + block: + - name: "1.1.4.1 | AUDIT | Ensure separate partition exists for /var/tmp | Absent" + ansible.builtin.debug: + msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" + + - name: "1.1.4.1 | AUDIT | Ensure separate partition exists for /var/tmp | Present" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '1.1.4.1' + required_mount: '/var/tmp' + when: + - required_mount not in mount_names + - rhel9cis_rule_1_1_4_1 + tags: + - level2-server + - level2-workstation + - audit + - mounts + - rule_1.1.4.1 + +# skips if mount is absent +- name: | + "1.1.4.2 | PATCH | Ensure noexec option set on /var/tmp partition" + "1.1.4.3 | PATCH | Ensure nosuid option set on /var/tmp partition" + "1.1.4.4 | PATCH | Ensure nodev option set on /var/tmp partition" + ansible.builtin.mount: + name: /var/tmp + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + state: present + opts: defaults,{% if rhel9cis_rule_1_1_4_2 %}noexec,{% endif %}{% if rhel9cis_rule_1_1_4_3 %}nosuid,{% endif %}{% if rhel9cis_rule_1_1_4_4 %}nodev{% endif %} + loop: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.device }}" + notify: Change_requires_reboot + when: + - item.mount == "/var/tmp" + - rhel9cis_rule_1_1_4_2 or + rhel9cis_rule_1_1_4_3 or + rhel9cis_rule_1_1_4_4 + tags: + - level1-server + - level1-workstation + - patch + - mounts + - skip_ansible_lint + - rule_1.1.4.2 + - rule_1.1.4.3 + - rule_1.1.4.4 diff --git a/tasks/section_1/cis_1.1.5.x.yml b/tasks/section_1/cis_1.1.5.x.yml new file mode 100644 index 0000000..1707f30 --- /dev/null +++ b/tasks/section_1/cis_1.1.5.x.yml @@ -0,0 +1,53 @@ +--- + +- name: "1.1.5.1 | AUDIT | Ensure separate partition exists for /var/log" + block: + - name: "1.1.5.1 | AUDIT | Ensure separate partition exists for /var/log | Absent" + ansible.builtin.debug: + msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" + + - name: "1.1.5.1 | AUDIT | Ensure separate partition exists for /var/log | Present" + ansible.builtin.import_tasks: warning_facts.yml + + vars: + warn_control_id: '1.1.5.1' + required_mount: '/var/log' + when: + - required_mount not in mount_names + - rhel9cis_rule_1_1_5_1 + tags: + - level2-server + - level2-workstation + - audit + - mounts + - rule_1.1.5.1 + - skip_ansible_lint + +- name: | + "1.1.5.2 | PATCH | Ensure nodev option set on /var/log partition" + "1.1.5.3 | PATCH | Ensure noexec option set on /var/log partition" + "1.1.5.4 | PATCH | Ensure nosuid option set on /var/log partition" + ansible.builtin.mount: + name: /var/log + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + state: present + opts: defaults,{% if rhel9cis_rule_1_1_5_2 %}nodev,{% endif %}{% if rhel9cis_rule_1_1_5_3 %}noexec,{% endif %}{% if rhel9cis_rule_1_1_5_4 %}nosuid{% endif %} + loop: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.device }}" + notify: Change_requires_reboot + when: + - item.mount == "/var/log" + - rhel9cis_rule_1_1_5_2 or + rhel9cis_rule_1_1_5_3 or + rhel9cis_rule_1_1_5_4 + tags: + - level1-server + - level1-workstation + - patch + - mounts + - skip_ansible_lint + - rule_1.1.5.2 + - rule_1.1.5.3 + - rule_1.1.5.4 diff --git a/tasks/section_1/cis_1.1.6.x.yml b/tasks/section_1/cis_1.1.6.x.yml new file mode 100644 index 0000000..274f668 --- /dev/null +++ b/tasks/section_1/cis_1.1.6.x.yml @@ -0,0 +1,52 @@ +--- + +- name: "1.1.6.1 | AUDIT | Ensure separate partition exists for /var/log/audit" + block: + - name: "1.1.6.1 | AUDIT | Ensure separate partition exists for /var/log/audit | Absent" + ansible.builtin.debug: + msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" + + - name: "1.1.6.1 | AUDIT | Ensure separate partition exists for /var/log/audit | Present" + ansible.builtin.import_tasks: warning_facts.yml + + vars: + warn_control_id: '1.1.6.1' + required_mount: '/var/log/audit' + when: + - required_mount not in mount_names + - rhel9cis_rule_1_1_6_1 + tags: + - level2-server + - level2-workstation + - audit + - mounts + - rule_1.1.6.1 + +- name: | + "1.1.6.2 | PATCH | Ensure noexec option set on /var/log/audit partition" + "1.1.6.3 | PATCH | Ensure nodev option set on /var/log/audit partition" + "1.1.6.4 | PATCH | Ensure nosuid option set on /var/log/audit partition" + ansible.builtin.mount: + name: /var/log/audit + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + state: present + opts: defaults,{% if rhel9cis_rule_1_1_6_2 %}noexec,{% endif %}{% if rhel9cis_rule_1_1_6_3 %}nodev,{% endif %}{% if rhel9cis_rule_1_1_6_4 %}nosuid{% endif %} + loop: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.device }}" + notify: Change_requires_reboot + when: + - item.mount == "/var/log/audit" + - rhel9cis_rule_1_1_6_2 or + rhel9cis_rule_1_1_6_3 or + rhel9cis_rule_1_1_6_4 + tags: + - level1-server + - level1-workstation + - patch + - mounts + - skip_ansible_lint + - rule_1.1.6.2 + - rule_1.1.6.3 + - rule_1.1.6.4 diff --git a/tasks/section_1/cis_1.1.7.x.yml b/tasks/section_1/cis_1.1.7.x.yml new file mode 100644 index 0000000..7f16610 --- /dev/null +++ b/tasks/section_1/cis_1.1.7.x.yml @@ -0,0 +1,52 @@ +--- + +- name: "1.1.7.1 | AUDIT | Ensure separate partition exists for /home" + block: + - name: "1.1.7.1 | AUDIT | Ensure separate partition exists for /home | Absent" + ansible.builtin.debug: + msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" + + - name: "1.1.7.1 | AUDIT | Ensure separate partition exists for /home | Present" + ansible.builtin.import_tasks: warning_facts.yml + + vars: + warn_control_id: '1.1.7.1' + required_mount: '/home' + when: + - required_mount not in mount_names + - rhel9cis_rule_1_1_7_1 + tags: + - level2-server + - level2-workstation + - audit + - mounts + - rule_1.1.7.1 + - skip_ansible_lint + +- name: | + "1.1.7.2 | PATCH | Ensure nodev option set on /home partition + 1.1.7.3 | PATCH | Ensure nosuid option set on /home partition" + ansible.builtin.mount: + name: /home + src: "{{ item.device }}" + fstype: "{{ item.fstype }}" + state: present + opts: defaults,{% if rhel9cis_rule_1_1_7_2 %}nodev,{% endif %}{% if rhel9cis_rule_1_1_7_3 %}nosuid,{% endif %} + loop: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.device }}" + notify: Change_requires_reboot + when: + - item.mount == "/home" + - rhel9cis_rule_1_1_7_1 + - rhel9cis_rule_1_1_7_2 or + rhel9cis_rule_1_1_7_3 + tags: + - level1-server + - level1-workstation + - patch + - mounts + - rule_1.1.7.2 + - rule_1.1.7.3 + - rule_1.1.7.4 + - skip_ansible_lint diff --git a/tasks/section_1/cis_1.1.8.x.yml b/tasks/section_1/cis_1.1.8.x.yml new file mode 100644 index 0000000..3b85af3 --- /dev/null +++ b/tasks/section_1/cis_1.1.8.x.yml @@ -0,0 +1,49 @@ +--- + +# Skips if mount is absent +- name: "1.1.8.1 | AUDIT | Ensure /dev/shm is a separate partition" + block: + - name: "1.1.8.1 | AUDIT | Ensure /dev/shm is a separate partition | Absent" + ansible.builtin.debug: + msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" + + - name: "1.1.8.1 | AUDIT | Ensure separate partition exists for /home | Present" + ansible.builtin.import_tasks: warning_facts.yml + + vars: + warn_control_id: '1.1.8.1' + required_mount: '/dev/shm' + when: + - required_mount not in mount_names + - rhel9cis_rule_1_1_8_1 + tags: + - level1-server + - level1-workstation + - audit + - mounts + - rule_1.1.8.1 + - skip_ansible_lint + +- name: | + "1.1.8.2 | PATCH | Ensure nodev option set on /dev/shm partition | Set nodev option + 1.1.8.3 | PATCH | Ensure noexec option set on /dev/shm partition | Set nosuid option + 1.1.8.4 | PATCH | Ensure nosuid option set on /dev/shm partition | Set noexec option" + ansible.builtin.mount: + name: /dev/shm + src: tmpfs + fstype: tmpfs + state: mounted + opts: defaults,{% if rhel9cis_rule_1_1_8_2 %}nodev,{% endif %}{% if rhel9cis_rule_1_1_8_3 %}noexec,{% endif %}{% if rhel9cis_rule_1_1_8_4 %}nosuid{% endif %} + notify: Change_requires_reboot + when: + - rhel9cis_rule_1_1_8_2 or + rhel9cis_rule_1_1_8_3 or + rhel9cis_rule_1_1_8_4 + tags: + - level1-server + - level1-workstation + - patch + - mounts + - rule_1.1.8.2 + - rule_1.1.8.3 + - rule_1.1.8.4 diff --git a/tasks/section_1/cis_1.1.x.yml b/tasks/section_1/cis_1.1.x.yml new file mode 100644 index 0000000..0496300 --- /dev/null +++ b/tasks/section_1/cis_1.1.x.yml @@ -0,0 +1,35 @@ +--- + +- name: "1.1.9 | PATCH | Disable USB Storage" + block: + - name: "1.1.9 | PATCH | Disable USB Storage | Edit modprobe config" + ansible.builtin.lineinfile: + path: /etc/modprobe.d/CIS.conf + regexp: "^(#)?install usb-storage(\\s|$)" + line: "install usb-storage /bin/true" + create: true + owner: root + group: root + mode: 0600 + + - name: "1.1.9 | PATCH | Disable USB Storage | Edit modprobe config" + ansible.builtin.modprobe: + name: usb-storage + state: absent + + - name: "1.1.9 | PATCH | Disable USB Storage | blacklist" + ansible.builtin.lineinfile: + path: /etc/modprobe.d/blacklist.conf + regexp: "^(#)?blacklist usb-storage(\\s|$)" + line: "blacklist usb-storage" + create: true + mode: 0600 + when: + - rhel9cis_rule_1_1_9 + tags: + - level1-server + - level2-workstation + - patch + - mounts + - removable_storage + - rule_1.1.9 diff --git a/tasks/section_1/cis_1.10.yml b/tasks/section_1/cis_1.10.yml new file mode 100644 index 0000000..c43e445 --- /dev/null +++ b/tasks/section_1/cis_1.10.yml @@ -0,0 +1,16 @@ +--- + +- name: "1.10 | PATCH | Ensure system-wide crypto policy is not legacy" + ansible.builtin.shell: | + update-crypto-policies --set "{{ rhel9cis_crypto_policy }}" + update-crypto-policies + notify: Change_requires_reboot + when: + - rhel9cis_rule_1_10 + - system_wide_crypto_policy['stdout'] == 'LEGACY' + tags: + - level1-server + - level1-workstation + - no system_is_ec2 + - patch + - rule_1.10 diff --git a/tasks/section_1/cis_1.2.1.x.yml b/tasks/section_1/cis_1.2.1.x.yml deleted file mode 100644 index a5a8d71..0000000 --- a/tasks/section_1/cis_1.2.1.x.yml +++ /dev/null @@ -1,122 +0,0 @@ ---- - -- name: "1.2.1.1 | AUDIT | Ensure GPG keys are configured" - when: - - rhel9cis_rule_1_2_1_1 - - ansible_facts.distribution == "RedHat" or - ansible_facts.distribution == "Rocky" or - ansible_facts.distribution == "AlmaLinux" - tags: - - level1-server - - level1-workstation - - manual - - patch - - rule_1.2.1.1 - - NIST800-53R5_SI-2 - block: - - name: "1.2.1.1 | AUDIT | Ensure GPG keys are configured | List installed pubkey keys" - ansible.builtin.shell: "rpm -qa | grep {{ os_gpg_key_pubkey_name }}" # noqa command-instead-of-module - changed_when: false - failed_when: false - register: discovered_os_installed_pub_keys - - - name: "1.2.1.1 | AUDIT | Ensure GPG keys are configured | Query found keys" - ansible.builtin.shell: | - 'rpm -q --queryformat "%{PACKAGER} %{VERSION}\\n" {{ os_gpg_key_pubkey_name }} | grep "{{ os_gpg_key_pubkey_content }}"' - changed_when: false - failed_when: false - register: discovered_os_gpg_key_check - - - name: "1.2.1.1 | AUDIT | Ensure GPG keys are configured | If expected keys fail" - when: - - discovered_os_installed_pub_keys.rc == 1 or - discovered_os_gpg_key_check.rc == 1 - ansible.builtin.fail: - msg: Installed GPG Keys do not meet expected values or expected keys are not installed - -- name: "1.2.1.2 | PATCH | Ensure gpgcheck is globally activated" - when: rhel9cis_rule_1_2_1_2 - tags: - - level1-server - - level1-workstation - - patch - - rule_1.2.1.2 - - NIST800-53R5_SI-2 - block: - - name: "1.2.1.2 | AUDIT | Ensure gpgcheck is globally activated | Find repos" - ansible.builtin.find: - paths: /etc/yum.repos.d - patterns: "*.repo" - register: discovered_yum_repos - - - name: "1.2.1.2 | PATCH | Ensure gpgcheck is globally activated | Update yum.repos" - ansible.builtin.replace: - name: "{{ item.path }}" - regexp: ^gpgcheck\s*=\s*0 - replace: "gpgcheck=1" - loop: "{{ discovered_yum_repos.files }}" - loop_control: - label: "{{ item.path }}" - -- name: "1.2.1.3 | AUDIT | Ensure repo_gpgcheck is globally activated" - when: - - rhel9cis_rule_1_2_1_3 - - rhel9cis_rule_enable_repogpg - - not rhel9cis_rhel_default_repo - tags: - - level1-server - - level1-workstation - - manual - - audit - - rule_1.2.1.3 - - NIST800-53R5_SI-2 - block: - - name: "1.2.1.3 | PATCH | Ensure repo_gpgcheck is globally activated | dnf.conf" - ansible.builtin.lineinfile: - path: /etc/dnf/dnf.conf - regexp: '^repo_gpgcheck' - line: repo_gpgcheck=1 - - - name: "1.2.1.3 | AUDIT| Ensure repo_gpgcheck is globally activated | get repo files" - ansible.builtin.find: - paths: /etc/yum.repos.d - patterns: "*.repo" - register: discovered_repo_files - - - name: "1.2.1.3 | PATCH | Ensure repo_gpgcheck is globally activated | amend repo files" - ansible.builtin.replace: - path: "{{ item.path }}" - regexp: ^repo_gpgcheck\s*=s*0 - replace: repo_gpgcheck=1 - loop: "{{ discovered_repo_files.files }}" - loop_control: - label: "{{ item.path }}" - -- name: "1.2.1.4 | AUDIT | Ensure package manager repositories are configured" - when: rhel9cis_rule_1_2_1_4 - tags: - - level1-server - - level1-workstation - - manual - - audit - - rule_1.2.1.4 - - NIST800-53R5_SI-2 - vars: - warn_control_id: '1.2.1.4' - block: - - name: "1.2.1.4 | AUDIT | Ensure package manager repositories are configured | Get repo list" - ansible.builtin.command: dnf repolist - changed_when: false - failed_when: false - check_mode: false - register: discovered_dnf_configured - - - name: "1.2.1.4 | AUDIT | Ensure package manager repositories are configured | Display repo list" - ansible.builtin.debug: - msg: - - "Warning!! Below are the configured repos. Please review and make sure all align with site policy" - - "{{ discovered_dnf_configured.stdout_lines }}" - - - name: "1.2.1.4 | AUDIT | Ensure package manager repositories are configured | Warn Count" - ansible.builtin.import_tasks: - file: warning_facts.yml diff --git a/tasks/section_1/cis_1.2.2.x.yml b/tasks/section_1/cis_1.2.2.x.yml deleted file mode 100644 index 2ccb59f..0000000 --- a/tasks/section_1/cis_1.2.2.x.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- - -- name: "1.2.2.1 | PATCH | Ensure updates, patches, and additional security software are installed" - when: - - rhel9cis_rule_1_2_2_1 - - not system_is_ec2 - tags: - - level1-server - - level1-workstation - - patch - - rule_1.2.2.1 - - NIST800-53R5_SI-2 - ansible.builtin.package: - name: "*" - state: latest - notify: Change_requires_reboot diff --git a/tasks/section_1/cis_1.2.x.yml b/tasks/section_1/cis_1.2.x.yml new file mode 100644 index 0000000..2501732 --- /dev/null +++ b/tasks/section_1/cis_1.2.x.yml @@ -0,0 +1,121 @@ +--- + +- name: "1.2.1 | AUDIT | Ensure GPG keys are configured" + block: + - name: "1.2.1 | AUDIT | Ensure GPG keys are configured | list installed pubkey keys" + ansible.builtin.shell: "rpm -qa | grep {{ os_gpg_key_pubkey_name }}" + changed_when: false + failed_when: false + register: os_installed_pub_keys + + - name: "1.2.1 | AUDIT | Ensure GPG keys are configured | Query found keys" + ansible.builtin.shell: 'rpm -q --queryformat "%{PACKAGER} %{VERSION}\\n" {{ os_gpg_key_pubkey_name }} | grep "{{ os_gpg_key_pubkey_content }}"' + changed_when: false + failed_when: false + register: os_gpg_key_check + when: os_installed_pub_keys.rc == 0 + + - name: "1.2.1 | AUDIT | Ensure GPG keys are configured | expected keys fail" + ansible.builtin.fail: + msg: Installed GPG Keys do not meet expected values or keys installed that are not expected + when: + - os_installed_pub_keys.rc == 1 or + os_gpg_key_check.rc == 1 + when: + - rhel9cis_rule_1_2_1 + - ansible_distribution == "RedHat" or + ansible_distribution == "Rocky" or + ansible_distribution == "AlmaLinux" + tags: + - level1-server + - level1-workstation + - manual + - patch + - rule_1.2.1 + +- name: "1.2.2 | PATCH | Ensure gpgcheck is globally activated" + block: + - name: "1.2.2 | AUDIT | Ensure gpgcheck is globally activated | Find repos" + ansible.builtin.find: + paths: /etc/yum.repos.d + patterns: "*.repo" + register: yum_repos + + - name: "1.2.2 | PATCH | Ensure gpgcheck is globally activated | Update yum.repos" + ansible.builtin.replace: + name: "{{ item.path }}" + regexp: "^gpgcheck=0" + replace: "gpgcheck=1" + loop: "{{ yum_repos.files }}" + loop_control: + label: "{{ item.path }}" + when: + - rhel9cis_rule_1_2_2 + tags: + - level1-server + - level1-workstation + - patch + - rule_1.2.2 + +- name: "1.2.3 | AUDIT | Ensure package manager repositories are configured" + block: + - name: "1.2.3 | AUDIT | Ensure package manager repositories are configured | Get repo list" + ansible.builtin.shell: dnf repolist + changed_when: false + failed_when: false + register: dnf_configured + check_mode: false + + - name: "1.2.3 | AUDIT | Ensure package manager repositories are configured | Display repo list" + ansible.builtin.debug: + msg: + - "Warning!! Below are the configured repos. Please review and make sure all align with site policy" + - "{{ dnf_configured.stdout_lines }}" + + - name: "1.2.3 | AUDIT | Ensure package manager repositories are configured | Warn Count" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '1.2.3' + when: + - rhel9cis_rule_1_2_3 + tags: + - level1-server + - level1-workstation + - manual + - audit + - rule_1.2.3 + - skip_ansible_lint + +- name: "1.2.4 | AUDIT | Ensure repo_gpgcheck is globally activated" + block: + - name: "1.2.4 | PATCH | Ensure repo_gpgcheck is globally activated | dnf.conf" + ansible.builtin.lineinfile: + path: /etc/dnf/dnf.conf + regexp: '^repo_gpgcheck' + line: repo_gpgcheck=1 + + - name: "1.2.4 | AUDIT| Ensure repo_gpgcheck is globally activated | get repo files" + ansible.builtin.find: + paths: /etc/yum.repos.d + patterns: "*.repo" + register: repo_files + + - name: "1.2.4 | PATCH | Ensure repo_gpgcheck is globally activated | amend repo files" + ansible.builtin.replace: + path: "{{ item.path }}" + regexp: '^repo_gpgcheck( |)=( |)0' + replace: repo_gpgcheck=1 + loop: "{{ repo_files.files }}" + loop_control: + label: "{{ item.path }}" + + when: + - rhel9cis_rule_1_2_4 + - not rhel9cis_rhel_default_repo or ansible_distribution != 'RedHat' + - ansible_distribution != 'OracleLinux' + tags: + - level1-server + - level1-workstation + - manual + - audit + - rule_1.2.4 diff --git a/tasks/section_1/cis_1.3.1.x.yml b/tasks/section_1/cis_1.3.1.x.yml deleted file mode 100644 index ad7d844..0000000 --- a/tasks/section_1/cis_1.3.1.x.yml +++ /dev/null @@ -1,150 +0,0 @@ ---- - -- name: "1.3.1.1 | PATCH | Ensure SELinux is installed" - when: - - rhel9cis_rule_1_3_1_1 - - not rhel9cis_selinux_disable - tags: - - level1-server - - level1-workstation - - patch - - rule_1.3.1.1 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.package: - name: libselinux - state: present - -- name: "1.3.1.2 | PATCH | Ensure SELinux is not disabled in bootloader configuration" - when: - - rhel9cis_rule_1_3_1_2 - - not rhel9cis_selinux_disable - tags: - - level1-server - - level1-workstation - - scored - - patch - - rule_1.3.1.2 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.replace: - path: /etc/default/grub - regexp: '{{ item }}' - replace: '' - loop: - - selinux=0 - - enforcing=0 - ignore_errors: true # noqa ignore-errors - notify: Grub2cfg - -# State set to enforcing because control 1.3.1.5 requires enforcing to be set -- name: "1.3.1.3 | PATCH | Ensure SELinux policy is configured" - when: - - rhel9cis_rule_1_3_1_3 - - not rhel9cis_selinux_disable - tags: - - level1-server - - level1-workstation - - selinux - - patch - - rule_1.3.1.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.posix.selinux: - conf: /etc/selinux/config - policy: "{{ rhel9cis_selinux_pol }}" - state: "{{ rhel9cis_selinux_enforce }}" - -- name: "1.3.1.4 | PATCH | Ensure the SELinux state is not disabled" - when: - - rhel9cis_rule_1_3_1_4 - - not rhel9cis_selinux_disable - tags: - - level1-server - - level1-workstation - - selinux - - patch - - rule_1.3.1.4 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.posix.selinux: - conf: /etc/selinux/config - policy: "{{ rhel9cis_selinux_pol }}" - state: "{{ rhel9cis_selinux_enforce }}" - -- name: "1.3.1.5 | PATCH | Ensure the SELinux state is enforcing" - when: - - rhel9cis_selinux_enforce == 'enforcing' - - rhel9cis_rule_1_3_1_5 - - not rhel9cis_selinux_disable - tags: - - level2-server - - level2-workstation - - selinux - - patch - - rule_1.3.1.5 - - NIST800-53R4_AC-3 - - NIST800-53R4_SI-6 - ansible.posix.selinux: - conf: /etc/selinux/config - policy: "{{ rhel9cis_selinux_pol }}" - state: enforcing - -- name: "1.3.1.6 | AUDIT | Ensure no unconfined services exist" - when: - - rhel9cis_rule_1_3_1_6 - - not rhel9cis_selinux_disable - tags: - - level1-server - - level1-workstation - - audit - - services - - rule_1.3.1.6 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - warn_control_id: '1.3.1.6' - block: - - name: "1.3.1.6 | AUDIT | Ensure no unconfined services exist | Find the unconfined services" - ansible.builtin.shell: ps -eZ | grep unconfined_service_t | grep -Evw "tr|ps|egrep|bash|awk" | tr ':' ' ' | awk '{ print $NF }' - register: discovered_unconf_services - failed_when: false - changed_when: false - - - name: "1.3.1.6 | AUDIT | Ensure no unconfined services exist | Message on unconfined services" - when: discovered_unconf_services.stdout | length > 0 - ansible.builtin.debug: - msg: "Warning!! You have unconfined services: {{ discovered_unconf_services.stdout_lines }}" - - - name: "1.3.1.6 | AUDIT | Ensure no unconfined services exist | warning count" - when: discovered_unconf_services.stdout | length > 0 - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "1.3.1.7 | PATCH | Ensure the MCS Translation Service (mcstrans) is not installed" - when: rhel9cis_rule_1_3_1_7 - tags: - - level1-server - - level1-workstation - - patch - - rule_1.3.1.7 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.package: - name: mcstrans - state: absent - -- name: "1.3.1.8 | PATCH | Ensure SETroubleshoot is not installed" - when: - - rhel9cis_rule_1_3_1_8 - - "'setroubleshoot' in ansible_facts.packages" - tags: - - level1-server - - selinux - - patch - - rule_1.3.1.8 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.package: - name: setroubleshoot - state: absent diff --git a/tasks/section_1/cis_1.3.x.yml b/tasks/section_1/cis_1.3.x.yml new file mode 100644 index 0000000..1275d86 --- /dev/null +++ b/tasks/section_1/cis_1.3.x.yml @@ -0,0 +1,78 @@ +--- + +- name: "1.3.1 | PATCH | Ensure AIDE is installed" + block: + - name: "1.3.1 | PATCH | Ensure AIDE is installed | Install AIDE" + ansible.builtin.package: + name: aide + state: present + + - name: "1.3.1 | PATCH | Ensure AIDE is installed | Build AIDE DB" + ansible.builtin.shell: /usr/sbin/aide --init + changed_when: false + failed_when: false + async: 45 + poll: 0 + args: + creates: /var/lib/aide/aide.db.new.gz + when: not ansible_check_mode + + - name: "1.3.1 | PATCH | Ensure AIDE is installed | copy AIDE DB" + ansible.builtin.copy: + src: /var/lib/aide/aide.db.new.gz + dest: /var/lib/aide/aide.db.gz + remote_src: true + when: + - rhel9cis_config_aide + - rhel9cis_rule_1_3_1 + tags: + - level1-server + - level1-workstation + - aide + - patch + - rule_1.3.1 + +- name: "1.3.2 | PATCH | Ensure filesystem integrity is regularly checked" + ansible.builtin.cron: + name: Run AIDE integrity check + cron_file: "{{ rhel9cis_aide_cron['cron_file'] }}" + user: "{{ rhel9cis_aide_cron['cron_user'] }}" + minute: "{{ rhel9cis_aide_cron['aide_minute'] | default('0') }}" + hour: "{{ rhel9cis_aide_cron['aide_hour'] | default('5') }}" + day: "{{ rhel9cis_aide_cron['aide_day'] | default('*') }}" + month: "{{ rhel9cis_aide_cron['aide_month'] | default('*') }}" + weekday: "{{ rhel9cis_aide_cron['aide_weekday'] | default('*') }}" + job: "{{ rhel9cis_aide_cron['aide_job'] }}" + when: + - rhel9cis_rule_1_3_2 + - not system_is_ec2 + tags: + - level1-server + - level1-workstation + - aide + - file_integrity + - patch + - rule_1.3.2 + +- name: "1.3.3 | Ensure cryptographic mechanisms are used to protect the integrity of audit tools" + ansible.builtin.blockinfile: + path: /etc/aide.conf + marker: "# {mark} Audit tools - CIS benchmark - Ansible-lockdown" + block: | + /sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512 + /sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512 + /sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512 + /sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512 + /sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512 + /sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512 + validate: aide -D --config %s + when: + - rhel9cis_rule_1_3_2 + - not system_is_ec2 + tags: + - level1-server + - level1-workstation + - aide + - file_integrity + - patch + - rule_1.3.3 diff --git a/tasks/section_1/cis_1.4.x.yml b/tasks/section_1/cis_1.4.x.yml index 5969dff..ec27fa6 100644 --- a/tasks/section_1/cis_1.4.x.yml +++ b/tasks/section_1/cis_1.4.x.yml @@ -1,71 +1,44 @@ --- - name: "1.4.1 | PATCH | Ensure bootloader password is set" - when: - - rhel9cis_set_boot_pass - - rhel9cis_rule_1_4_1 - tags: - - level1-server - - level1-workstation - - grub - - patch - - rule_1.4.1 - - NIST800-53R5_AC-3 ansible.builtin.copy: - dest: /boot/grub2/user.cfg - content: "GRUB2_PASSWORD={{ rhel9cis_bootloader_password_hash }}" # noqa template-instead-of-copy - owner: root - group: root - mode: 'go-rwx' + dest: /boot/grub2/user.cfg + content: "GRUB2_PASSWORD={{ rhel9cis_bootloader_password_hash }}" # noqa template-instead-of-copy + owner: root + group: root + mode: 0600 notify: Grub2cfg + when: + - rhel9cis_set_boot_pass + - rhel9cis_rule_1_4_1 + tags: + - level1-server + - level1-workstation + - grub + - patch + - rule_1.4.1 - name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured" - when: rhel9cis_rule_1_4_2 - tags: - - level1-server - - level1-workstation - - grub - - patch - - rule_1.4.2 - - NIST800-53R5_AC-3 block: - - name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | bios based system" - when: rhel9cis_legacy_boot - ansible.builtin.file: - path: "/boot/grub2/{{ item.path }}" - owner: root - group: root - mode: "{{ item.mode }}" - state: touch - modification_time: preserve - access_time: preserve - loop: - - { path: 'grub.cfg', mode: 'u-x,go-rwx' } - - { path: 'grubenv', mode: 'u-x,go-rwx' } - - { path: 'user.cfg', mode: 'u-x,go-rwx' } + - name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured" + ansible.builtin.file: + path: "/boot/grub2/{{ item.path }}" + owner: root + group: root + mode: "{{ item.mode }}" + state: touch + modification_time: preserve + access_time: preserve + loop: + - { path: 'grub.cfg', mode: '0700' } + - { path: 'grubenv', mode: '0600' } + - { path: 'user.cfg', mode: '0600' } - - name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | efi based system" - when: not rhel9cis_legacy_boot - vars: - efi_mount_options: ['umask=0077', 'fmask=0077', 'uid=0', 'gid=0'] - block: - - name: "1.4.2 | AUDIT | Ensure permissions on bootloader config are configured | efi based system | capture current state" - ansible.builtin.shell: grep "^[^#;]" /etc/fstab | grep '/boot/efi' | awk -F" " '{print $4}' - changed_when: false - check_mode: false - register: discovered_efi_fstab - - - name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | efi based system | Build Options" - when: item not in discovered_efi_fstab.stdout - ansible.builtin.set_fact: - efi_mount_opts_addition: "{{ efi_mount_opts_addition + ',' + item }}" - loop: "{{ efi_mount_options }}" - - - name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | efi based system | Add mount options" - when: efi_mount_opts_addition | length > 0 - ansible.builtin.lineinfile: - path: /etc/fstab - regexp: (.*/boot/efi\s*\w*\s*){{ discovered_efi_fstab.stdout }}(.*) - line: \1{{ discovered_efi_fstab.stdout + efi_mount_opts_addition }}\2 - backrefs: true - notify: Remount /boot/efi + when: + - rhel9cis_rule_1_4_2 + tags: + - level1-server + - level1-workstation + - grub + - patch + - rule_1.4.2 diff --git a/tasks/section_1/cis_1.5.x.yml b/tasks/section_1/cis_1.5.x.yml index 992785b..3f80647 100644 --- a/tasks/section_1/cis_1.5.x.yml +++ b/tasks/section_1/cis_1.5.x.yml @@ -1,66 +1,48 @@ --- -- name: "1.5.1 | PATCH | Ensure address space layout randomization (ASLR) is enabled" - when: rhel9cis_rule_1_5_1 - tags: - - level1-server - - level1-workstation - - patch - - sysctl - - rule_1.5.1 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-6.1 - block: - - name: "1.5.1 | PATCH | Ensure address space layout randomization (ASLR) is enabled" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - - - name: "1.5.1 | PATCH | Ensure address space layout randomization (ASLR) is enabled" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-kernel_sysctl.conf" - -- name: "1.5.2 | PATCH | Ensure ptrace_scope is restricted" - when: rhel9cis_rule_1_5_2 - tags: - - level1-server - - level1-workstation - - patch - - sysctl - - rule_1.5.2 - block: - - name: "1.5.2 | PATCH | Ensure ptrace_scope is restricted" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - - - name: "1.5.2 | PATCH | Ensure ptrace_scope is restricted" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-kernel_sysctl.conf" - -- name: "1.5.3 | PATCH | Ensure core dump backtraces are disabled" - when: rhel9cis_rule_1_5_3 - tags: - - level1-server - - level1-workstation - - patch - - sysctl - - rule_1.5.3 - - NIST800-53R5_CM-6b +- name: "1.5.1 | PATCH | Ensure core dump storage is disabled" ansible.builtin.lineinfile: - path: /etc/systemd/coredump.conf - regexp: '(?#)^ProcessSizeMax\s*=\s*.*[1-9].*$' - line: 'ProcessSizeMax=0' - -- name: "1.5.4 | PATCH | Ensure core dump storage is disabled" - when: - - rhel9cis_rule_1_5_4 - - prelim_systemd_coredump.stat.exists - tags: - - level1-server - - level1-workstation - - patch - - rule_1.5.4 - ansible.builtin.lineinfile: - path: /etc/systemd/coredump.conf - regexp: '^Storage\s*=\s*(?!none).*' - line: 'Storage=none' + path: /etc/systemd/coredump.conf + regexp: '^Storage\s*=\s*(?!none).*' + line: 'Storage=none' notify: Systemd daemon reload + when: + - rhel9cis_rule_1_5_1 + - systemd_coredump.stat.exists + tags: + - level1-server + - level1-workstation + - patch + - rule_1.5.1 + +- name: "1.5.2 | PATCH | Ensure core dump backtraces are disabled" + ansible.builtin.lineinfile: + path: /etc/systemd/coredump.conf + regexp: '^ProcessSizeMax\s*=\s*.*[1-9]$' + line: 'ProcessSizeMax=0' + when: + - rhel9cis_rule_1_5_2 + tags: + - level1-server + - level1-workstation + - patch + - sysctl + - rule_1.5.2 + +- name: "1.5.3 | PATCH | Ensure address space layout randomization (ASLR) is enabled" + block: + - name: "1.5.3 | PATCH | Ensure address space layout randomization (ASLR) is enabled" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true + + - name: "1.5.3 | PATCH | Ensure address space layout randomization (ASLR) is enabled" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-kernel_sysctl.conf" + when: + - rhel9cis_rule_1_5_3 + tags: + - level1-server + - level1-workstation + - patch + - sysctl + - rule_1.5.3 diff --git a/tasks/section_1/cis_1.6.1.x.yml b/tasks/section_1/cis_1.6.1.x.yml new file mode 100644 index 0000000..f05143c --- /dev/null +++ b/tasks/section_1/cis_1.6.1.x.yml @@ -0,0 +1,132 @@ +--- + +- name: "1.6.1.1 | PATCH | Ensure SELinux is installed" + ansible.builtin.package: + name: libselinux + state: present + when: + - rhel9cis_rule_1_6_1_1 + tags: + - level1-server + - level1-workstation + - patch + - rule_1.6.1.1 + +- name: "1.6.1.2 | PATCH | Ensure SELinux is not disabled in bootloader configuration" + ansible.builtin.replace: + path: /etc/default/grub + regexp: '{{ item }}' + replace: '' + loop: + - selinux=0 + - enforcing=0 + register: selinux_grub_patch + ignore_errors: true # noqa ignore-errors + notify: Grub2cfg + when: + - rhel9cis_rule_1_6_1_2 + tags: + - level1-server + - level1-workstation + - scored + - patch + - rule_1.6.1.2 + +# State set to enforcing because control 1.6.1.5 requires enforcing to be set +- name: "1.6.1.3 | PATCH | Ensure SELinux policy is configured" + ansible.posix.selinux: + conf: /etc/selinux/config + policy: "{{ rhel9cis_selinux_pol }}" + state: "{{ rhel9cis_selinux_enforce }}" + when: + - not rhel9cis_selinux_disable + - rhel9cis_rule_1_6_1_3 + tags: + - level1-server + - level1-workstation + - selinux + - patch + - rule_1.6.1.3 + +- name: "1.6.1.4 | PATCH | Ensure the SELinux state is not disabled" + ansible.posix.selinux: + conf: /etc/selinux/config + policy: "{{ rhel9cis_selinux_pol }}" + state: "{{ rhel9cis_selinux_enforce }}" + when: + - not rhel9cis_selinux_disable + - rhel9cis_rule_1_6_1_4 + tags: + - level1-server + - level1-workstation + - selinux + - patch + - rule_1.6.1.4 + +- name: "1.6.1.5 | PATCH | Ensure the SELinux state is enforcing" + ansible.posix.selinux: + conf: /etc/selinux/config + policy: "{{ rhel9cis_selinux_pol }}" + state: enforcing + when: + - not rhel9cis_selinux_disable + - rhel9cis_selinux_enforce == 'enforcing' + - rhel9cis_rule_1_6_1_5 + tags: + - level2-server + - level2-workstation + - selinux + - patch + - rule_1.6.1.5 + +- name: "1.6.1.6 | AUDIT | Ensure no unconfined services exist" + block: + - name: "1.6.1.6 | AUDIT | Ensure no unconfined services exist | Find the unconfined services" + ansible.builtin.shell: ps -eZ | grep unconfined_service_t | egrep -vw "tr|ps|egrep|bash|awk" | tr ':' ' ' | awk '{ print $NF }' + register: rhelcis_1_6_1_6_unconf_services + failed_when: false + changed_when: false + + - name: "1.6.1.6 | AUDIT | Ensure no unconfined services exist | Message on unconfined services" + ansible.builtin.debug: + msg: "Warning!! You have unconfined services: {{ rhelcis_1_6_1_6_unconf_services.stdout_lines }}" + when: rhelcis_1_6_1_6_unconf_services.stdout | length > 0 + + - name: "1.6.1.6 | AUDIT | Ensure no unconfined services exist | warning count" + ansible.builtin.import_tasks: warning_facts.yml + when: rhelcis_1_6_1_6_unconf_services.stdout | length > 0 + vars: + warn_control_id: '1.6.1.6' + when: + - rhel9cis_rule_1_6_1_6 + tags: + - level1-server + - level1-workstation + - audit + - services + - rule_1.6.1.6 + +- name: "1.6.1.7 | PATCH | Ensure SETroubleshoot is not installed" + ansible.builtin.package: + name: setroubleshoot + state: absent + when: + - rhel9cis_rule_1_6_1_7 + - "'setroubleshoot' in ansible_facts.packages" + tags: + - level1-server + - selinux + - patch + - rule_1.6.1.7 + +- name: "1.6.1.8 | PATCH | Ensure the MCS Translation Service (mcstrans) is not installed" + ansible.builtin.package: + name: mcstrans + state: absent + when: + - rhel9cis_rule_1_6_1_8 + tags: + - level1-server + - level1-workstation + - patch + - rule_1.6.1.8 diff --git a/tasks/section_1/cis_1.6.x.yml b/tasks/section_1/cis_1.6.x.yml deleted file mode 100644 index 8aace04..0000000 --- a/tasks/section_1/cis_1.6.x.yml +++ /dev/null @@ -1,193 +0,0 @@ ---- - -- name: "1.6.1 | AUDIT | Ensure system-wide crypto policy is not legacy" - when: - - rhel9cis_rule_1_6_1 - - rhel9cis_crypto_policy_ansiblemanaged - tags: - - level1-server - - level1-workstation - - automated - - patch - - crypto - - rule_1.6.1 - - NIST800-53R5_SC-6 - ansible.builtin.debug: - msg: "Captured in prelim to ensure not LEGACY. Runs handler to update" - notify: - - Update Crypto Policy - - Set Crypto Policy - -- name: "1.6.2 | PATCH | Ensure system wide crypto policy is not set in sshd configuration" - when: rhel9cis_rule_1_6_2 - tags: - - level1-server - - level1-workstation - - sshd - - automated - - patch - - rule_1.6.2 - - NIST800-53R5_SC-8 - - NIST800-53R5_IA-5 - - NIST800-53R5_AC-17 - - NIST800-53R5_SC-6 - ansible.builtin.lineinfile: - path: /etc/sysconfig/sshd - regexp: ^CRYPTO_POLICY\s*= - state: absent - notify: Restart sshd - -- name: "1.6.3 | PATCH | Ensure system wide crypto policy disables sha1 hash and signature support | Add submodule exclusion" - when: - - rhel9cis_rule_1_6_3 - - "'NO-SHA1' not in rhel9cis_crypto_policy_module" - - rhel9cis_crypto_policy_ansiblemanaged - tags: - - level1-server - - level1-workstation - - automated - - patch - - crypto - - rule_1.6.3 - - NIST800-53R5_SC-6 - block: - - name: "1.6.3 | PATCH | Ensure system wide crypto policy disables sha1 hash and signature support" - ansible.builtin.template: - src: etc/crypto-policies/policies/modules/NO-SHA1.pmod.j2 - dest: /etc/crypto-policies/policies/modules/NO-SHA1.pmod - owner: root - group: root - mode: 'g-wx,o-rwx' - register: discovered_no_sha1_template - - - name: "1.6.3 | PATCH | Ensure system wide crypto policy disables sha1 hash and signature support | submodule to crypto policy modules" - ansible.builtin.set_fact: - rhel9cis_crypto_policy_module: "{{ rhel9cis_crypto_policy_module + ':' + 'NO-SHA1' }}" - changed_when: discovered_no_sha1_template is changed # noqa: no-handler - notify: - - Update Crypto Policy - - Set Crypto Policy - -- name: "1.6.4 | PATCH | Ensure system wide crypto policy disables macs less than 128 bits" - when: - - rhel9cis_rule_1_6_4 - - "'NO-WEAKMAC' not in rhel9cis_crypto_policy_module" - - rhel9cis_crypto_policy_ansiblemanaged - tags: - - level1-server - - level1-workstation - - automated - - patch - - crypto - - rule_1.6.4 - - NIST800-53R5_SC-6 - block: - - name: "1.6.4 | PATCH | Ensure system wide crypto policy disables macs less than 128 bits | Add submodule exclusion" - ansible.builtin.template: - src: etc/crypto-policies/policies/modules/NO-WEAKMAC.pmod.j2 - dest: /etc/crypto-policies/policies/modules/NO-WEAKMAC.pmod - owner: root - group: root - mode: 'g-wx,o-rwx' - register: discovered_no_weakmac_template - - - name: "1.6.4 | PATCH | Ensure system wide crypto policy disables macs less than 128 bits | submodule to crypto policy modules" - ansible.builtin.set_fact: - rhel9cis_crypto_policy_module: "{{ rhel9cis_crypto_policy_module + ':' + 'NO-WEAKMAC' }}" - changed_when: discovered_no_weakmac_template is changed # noqa: no-handler - notify: - - Update Crypto Policy - - Set Crypto Policy - -- name: "1.6.5 | PATCH | Ensure system wide crypto policy disables cbc for ssh" - when: - - rhel9cis_rule_1_6_5 - - "'NO-SSHCBC' not in rhel9cis_crypto_policy_module" - - rhel9cis_crypto_policy_ansiblemanaged - tags: - - level1-server - - level1-workstation - - automated - - patch - - crypto - - rule_1.6.5 - - NIST800-53R5_SC-6 - block: - - name: "1.6.5 | PATCH | Ensure system wide crypto policy disables cbc for ssh | Add submodule exclusion" - ansible.builtin.template: - src: etc/crypto-policies/policies/modules/NO-SSHCBC.pmod.j2 - dest: /etc/crypto-policies/policies/modules/NO-SSHCBC.pmod - owner: root - group: root - mode: 'g-wx,o-rwx' - register: discovered_no_sshcbc_template - - - name: "1.6.5 | PATCH | Ensure system wide crypto policy disables cbc for ssh | submodule to crypto policy modules" - ansible.builtin.set_fact: - rhel9cis_crypto_policy_module: "{{ rhel9cis_crypto_policy_module + ':' + 'NO-SSHCBC' }}" - changed_when: discovered_no_sshcbc_template is changed # noqa: no-handler - notify: - - Update Crypto Policy - - Set Crypto Policy - -- name: "1.6.6 | PATCH | Ensure system wide crypto policy disables chacha20-poly1305 for ssh" - when: - - rhel9cis_rule_1_6_6 - - "'NO-SSHWEAKCIPHERS' not in rhel9cis_crypto_policy_module" - - rhel9cis_crypto_policy_ansiblemanaged - tags: - - level1-server - - level1-workstation - - automated - - patch - - crypto - - rule_1.6.6 - - NIST800-53R5_SC-6 - block: - - name: "1.6.6 | PATCH | Ensure system wide crypto policy disables chacha20-poly1305 for ssh | Add submodule exclusion" - ansible.builtin.template: - src: etc/crypto-policies/policies/modules/NO-SSHWEAKCIPHERS.pmod.j2 - dest: /etc/crypto-policies/policies/modules/NO-SSHWEAKCIPHERS.pmod - owner: root - group: root - mode: 'g-wx,o-rwx' - register: discovered_no_sshweakciphers_template - - - name: "1.6.6 | PATCH | Ensure system wide crypto policy disables chacha20-poly1305 for ssh | submodule to crypto policy modules" - ansible.builtin.set_fact: - rhel9cis_crypto_policy_module: "{{ rhel9cis_crypto_policy_module + ':' + 'NO-SSHWEAKCIPHERS' }}" - changed_when: discovered_no_sshweakciphers_template is changed # noqa: no-handler - notify: - - Update Crypto Policy - - Set Crypto Policy - -- name: "1.6.7 | PATCH | Ensure system wide crypto policy disables EtM for ssh" - when: - - rhel9cis_rule_1_6_7 - - "'NO-SSHETM' not in rhel9cis_crypto_policy_module" - - rhel9cis_crypto_policy_ansiblemanaged - tags: - - level1-server - - level1-workstation - - automated - - patch - - crypto - - rule_1.6.7 - - NIST800-53R5_SC-6 - block: - - name: "1.6.7 | PATCH | Ensure system wide crypto policy disables EtM for ssh | Add submodule exclusion" - ansible.builtin.template: - src: etc/crypto-policies/policies/modules/NO-SSHETM.pmod.j2 - dest: /etc/crypto-policies/policies/modules/NO-SSHETM.pmod - owner: root - group: root - mode: 'g-wx,o-rwx' - register: discovered_no_sshetm_template - - - name: "1.6.7 | PATCH | Ensure system wide crypto policy disables EtM for ssh | submodule to crypto policy modules" - ansible.builtin.set_fact: - rhel9cis_crypto_policy_module: "{{ rhel9cis_crypto_policy_module + ':' + 'NO-SSHETM' }}" - changed_when: discovered_no_sshetm_template is changed # noqa: no-handler - notify: - - Update Crypto Policy - - Set Crypto Policy diff --git a/tasks/section_1/cis_1.7.x.yml b/tasks/section_1/cis_1.7.x.yml index 7f45476..1c20dca 100644 --- a/tasks/section_1/cis_1.7.x.yml +++ b/tasks/section_1/cis_1.7.x.yml @@ -1,102 +1,93 @@ --- - name: "1.7.1 | PATCH | Ensure message of the day is configured properly" - when: rhel9cis_rule_1_7_1 - tags: - - level1-server - - level1-workstation - - banner - - patch - - rule_1.7.1 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-3 - - NIST800-53R5_CM-6 ansible.builtin.template: - src: etc/motd.j2 - dest: /etc/motd - owner: root - group: root - mode: 'u-x,go-wx' + src: etc/motd.j2 + dest: /etc/motd + owner: root + group: root + mode: 0644 + when: + - rhel9cis_rule_1_7_1 + tags: + - level1-server + - level1-workstation + - banner + - patch + - rule_1.7.1 - name: "1.7.2 | PATCH | Ensure local login warning banner is configured properly" - when: rhel9cis_rule_1_7_2 - tags: - - level1-server - - level1-workstation - - patch - - rule_1.7.2 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-3 - - NIST800-53R5_CM-6 ansible.builtin.template: - src: etc/issue.j2 - dest: /etc/issue - owner: root - group: root - mode: 'go-wx' + src: etc/issue.j2 + dest: /etc/issue + owner: root + group: root + mode: 0644 + when: + - rhel9cis_rule_1_7_2 + tags: + - level1-server + - level1-workstation + - patch + - rule_1.7.2 - name: "1.7.3 | PATCH | Ensure remote login warning banner is configured properly" - when: rhel9cis_rule_1_7_3 - tags: - - level1-server - - level1-workstation - - banner - - patch - - rule_1.7.3 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-3 - - NIST800-53R5_CM-6 ansible.builtin.template: - src: etc/issue.net.j2 - dest: /etc/issue.net - owner: root - group: root - mode: 'go-wx' + src: etc/issue.net.j2 + dest: /etc/issue.net + owner: root + group: root + mode: 0644 + when: + - rhel9cis_rule_1_7_3 + tags: + - level1-server + - level1-workstation + - banner + - patch + - rule_1.7.3 - name: "1.7.4 | PATCH | Ensure permissions on /etc/motd are configured" - when: rhel9cis_rule_1_7_4 - tags: - - level1-server - - level1-workstation - - perms - - patch - - rule_1.7.4 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 ansible.builtin.file: - path: /etc/motd - owner: root - group: root - mode: 'go-wx' + path: /etc/motd + owner: root + group: root + mode: 0644 + when: + - rhel9cis_rule_1_7_4 + tags: + - level1-server + - level1-workstation + - perms + - patch + - rule_1.7.4 - name: "1.7.5 | PATCH | Ensure permissions on /etc/issue are configured" - when: rhel9cis_rule_1_7_5 - tags: - - level1-server - - level1-workstation - - perms - - patch - - rule_1.7.5 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 ansible.builtin.file: - path: /etc/issue - owner: root - group: root - mode: 'go-wx' + path: /etc/issue + owner: root + group: root + mode: 0644 + when: + - rhel9cis_rule_1_7_5 + tags: + - level1-server + - level1-workstation + - perms + - patch + - rule_1.7.5 - name: "1.7.6 | PATCH | Ensure permissions on /etc/issue.net are configured" - when: rhel9cis_rule_1_7_6 - tags: - - level1-server - - level1-workstation - - perms - - patch - - rule_1.7.6 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 ansible.builtin.file: - path: /etc/issue.net - owner: root - group: root - mode: 'go-wx' + path: /etc/issue.net + owner: root + group: root + mode: 0644 + when: + - rhel9cis_rule_1_7_6 + tags: + - level1-server + - level1-workstation + - perms + - patch + - rule_1.7.6 diff --git a/tasks/section_1/cis_1.8.x.yml b/tasks/section_1/cis_1.8.x.yml index c6f91b3..4f6922f 100644 --- a/tasks/section_1/cis_1.8.x.yml +++ b/tasks/section_1/cis_1.8.x.yml @@ -1,264 +1,264 @@ --- - name: "1.8.1 | PATCH | Ensure GNOME Display Manager is removed" - when: - - rhel9cis_rule_1_8_1 - - "'gdm' in ansible_facts.packages" - - not rhel9cis_gui - tags: - - level2-server - - patch - - gui - - gdm - - rule_1.8.1 ansible.builtin.package: - name: gdm - state: absent + name: gdm + state: absent + when: + - rhel9cis_rule_1_8_1 + - "'gdm' in ansible_facts.packages" + - not rhel9cis_gui + tags: + - level2-server + - patch + - gui + - gdm + - rule_1.8.1 - name: "1.8.2 | PATCH | Ensure GDM login banner is configured" - when: - - rhel9cis_rule_1_8_2 - - rhel9cis_gui - tags: - - level1-server - - level1-workstation - - patch - - gui - - gdm - - rule_1.8.2 block: - - name: "1.8.2 | PATCH | Ensure GDM login banner is configured | gdm profile" - ansible.builtin.lineinfile: - path: /etc/dconf/profile/gdm - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - create: true - owner: root - group: root - mode: 'go-wx' - notify: Reload dconf - loop: - - { regexp: 'user-db', line: 'user-db:user' } - - { regexp: 'system-db', line: 'system-db:gdm' } - - { regexp: 'file-db', line: 'file-db:/usr/share/gdm/greeter-dconf-defaults' } + - name: "1.8.2 | PATCH | Ensure GDM login banner is configured | gdm profile" + ansible.builtin.lineinfile: + path: /etc/dconf/profile/gdm + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + create: true + owner: root + group: root + mode: 0644 + notify: Reload dconf + loop: + - { regexp: 'user-db', line: 'user-db:user' } + - { regexp: 'system-db', line: 'system-db:gdm' } + - { regexp: 'file-db', line: 'file-db:/usr/share/gdm/greeter-dconf-defaults' } - - name: "1.8.2 | PATCH | Ensure GDM login banner is configured | gdm profile" - ansible.builtin.template: - src: etc/dconf/db/gdm.d/01-banner-message.j2 - dest: /etc/dconf/db/gdm.d/01-banner-message - owner: root - group: root - mode: 'go-wx' - notify: Reload dconf + - name: "1.8.2 | PATCH | Ensure GDM login banner is configured | gdm profile" + ansible.builtin.template: + src: etc/dconf/db/gdm.d/01-banner-message.j2 + dest: /etc/dconf/db/gdm.d/01-banner-message + owner: root + group: root + mode: 0644 + notify: Reload dconf + when: + - rhel9cis_rule_1_8_2 + - rhel9cis_gui + tags: + - level1-server + - level1-workstation + - patch + - gui + - gdm + - rule_1.8.2 - name: "1.8.3 | PATCH | Ensure GDM disable-user-list option is enabled" - when: - - rhel9cis_rule_1_8_3 - - rhel9cis_gui - tags: - - level1-server - - level1-workstation - - patch - - gui - - rule_1.8.3 ansible.builtin.lineinfile: - path: "{{ item.file }}" - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - create: true - owner: root - group: root - mode: 'go-wx' + path: "{{ item.file }}" + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + create: true + owner: root + group: root + mode: 0644 notify: Reload dconf loop: - - { file: '/etc/dconf/profile/gdm', regexp: 'user-db', line: 'user-db:user' } - - { file: '/etc/dconf/profile/gdm', regexp: 'system-db', line: 'system-db:gdm' } - - { file: '/etc/dconf/profile/gdm', regexp: 'file-db', line: 'file-db:/usr/share/gdm/greeter-dconf-defaults'} - - { file: '/etc/dconf/db/gdm.d/00-login-screen', regexp: '\[org\/gnome\/login-screen\]', line: '[org/gnome/login-screen]' } - - { file: '/etc/dconf/db/gdm.d/00-login-screen', regexp: 'disable-user-list=', line: 'disable-user-list=true' } + - { file: '/etc/dconf/profile/gdm', regexp: 'user-db', line: 'user-db:user' } + - { file: '/etc/dconf/profile/gdm', regexp: 'system-db', line: 'system-db:gdm' } + - { file: '/etc/dconf/profile/gdm', regexp: 'file-db', line: 'file-db:/usr/share/gdm/greeter-dconf-defaults'} + - { file: '/etc/dconf/db/gdm.d/00-login-screen', regexp: '\[org\/gnome\/login-screen\]', line: '[org/gnome/login-screen]' } + - { file: '/etc/dconf/db/gdm.d/00-login-screen', regexp: 'disable-user-list=', line: 'disable-user-list=true' } + when: + - rhel9cis_rule_1_8_3 + - rhel9cis_gui + tags: + - level1-server + - level1-workstation + - patch + - gui + - rule_1.8.3 - name: "1.8.4 | PATCH | Ensure GDM screen locks when the user is idle" - when: - - rhel9cis_rule_1_8_4 - - rhel9cis_gui - tags: - - level1-server - - level1-workstation - - patch - - gui - - rule_1.8.4 block: - - name: "1.8.4 | PATCH | Ensure GDM screen locks when the user is idle | User profile" - ansible.builtin.lineinfile: - path: /etc/dconf/profile/user - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - create: true - owner: root - group: root - mode: 'go-wx' - loop: - - { regexp: '^user-db', line: 'user-db:user' } - - { regexp: '^system-db', line: 'system-db:local' } + - name: "1.8.4 | PATCH | Ensure GDM screen locks when the user is idle | User profile" + ansible.builtin.lineinfile: + path: /etc/dconf/profile/user + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + create: true + owner: root + group: root + mode: 0644 + loop: + - { regexp: '^user-db', line: 'user-db: user' } + - { regexp: '^system-db', line: 'system-db: local' } - - name: "1.8.4 | PATCH | Ensure GDM screen locks when the user is idle | Make db directory" - ansible.builtin.file: - path: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d" - owner: root - group: root - mode: 'go-w' - state: directory + - name: "1.8.4 | PATCH | Ensure GDM screen locks when the user is idle | Make db directory" + ansible.builtin.file: + path: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d" + owner: root + group: root + mode: 0755 + state: directory - - name: "1.8.4 | PATCH | Ensure GDM screen locks when the user is idle | Make conf file" - ansible.builtin.template: - src: etc/dconf/db/00-screensaver.j2 - dest: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/00-screensaver" - owner: root - group: root - mode: 'go-wx' - notify: Reload dconf - -- name: "1.8.5 | PATCH | Ensure GDM screen locks cannot be overridden" + - name: "1.8.4 | PATCH | Ensure GDM screen locks when the user is idle | Make conf file" + ansible.builtin.template: + src: etc/dconf/db/00-screensaver.j2 + dest: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/00-screensaver" + owner: root + group: root + mode: '0644' + notify: Reload dconf when: - - rhel9cis_rule_1_8_5 - - rhel9cis_gui + - rhel9cis_rule_1_8_4 + - rhel9cis_gui tags: - - level1-server - - level1-workstation - - patch - - gui - - rule_1.8.5 - block: - - name: "1.8.5 | PATCH | Ensure GDM screen locks cannot be overridden | Make lock directory" - ansible.builtin.file: - path: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/locks" - owner: root - group: root - mode: 'go-w' - state: directory + - level1-server + - level1-workstation + - patch + - gui + - rule_1.8.4 - - name: "1.8.5 | PATCH | Ensure GDM screen locks cannot be overridden | Make lock file" - ansible.builtin.template: - src: etc/dconf/db/00-screensaver_lock.j2 - dest: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/locks/00-screensaver_lock" - owner: root - group: root - mode: 'go-wx' - notify: Reload dconf +- name: "1.8.5 PATCH | Ensure GDM screen locks cannot be overridden" + block: + - name: "1.8.5 | PATCH | Ensure GDM screen locks cannot be overridden | Make lock directory" + ansible.builtin.file: + path: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/locks" + owner: root + group: root + mode: 0755 + state: directory + + - name: "1.8.5 | PATCH | Ensure GDM screen locks cannot be overridden | Make lock file" + ansible.builtin.template: + src: etc/dconf/db/00-screensaver_lock.j2 + dest: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/locks/00-screensaver" + owner: root + group: root + mode: 0644 + notify: Reload dconf + when: + - rhel9cis_rule_1_8_5 + - rhel9cis_gui + tags: + - level1-server + - level1-workstation + - patch + - gui + - rule_1.8.5 - name: "1.8.6 | PATCH | Ensure GDM automatic mounting of removable media is disabled" - when: - - rhel9cis_rule_1_8_6 - - rhel9cis_gui - tags: - - level1-server - - level2-workstation - - patch - - gui - - rule_1.8.6 ansible.builtin.template: - src: etc/dconf/db/00-media-automount.j2 - dest: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/00-media-automount" - owner: root - group: root - mode: 'go-wx' + src: etc/dconf/db/00-media-automount.j2 + dest: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/00-media-automount" + owner: root + group: root + mode: '0644' notify: Reload dconf + when: + - rhel9cis_rule_1_8_6 + - rhel9cis_gui + tags: + - level1-server + - level2-workstation + - patch + - gui + - rule_1.8.6 - name: "1.8.7 | PATCH | Ensure GDM disabling automatic mounting of removable media is not overridden" - when: - - rhel9cis_rule_1_8_7 - - rhel9cis_gui - tags: - - level1-server - - level2-workstation - - patch - - gui - - rule_1.8.7 block: - - name: "1.8.7 | PATCH | Ensure GDM disabling automatic mounting of removable media is not overridden | Make lock directory" - ansible.builtin.file: - path: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/locks" - owner: root - group: root - mode: 'go-w' - state: directory + - name: "1.8.7 | PATCH | Ensure GDM disabling automatic mounting of removable media is not overridden | Make lock directory" + ansible.builtin.file: + path: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/locks" + owner: root + group: root + mode: 0755 + state: directory - - name: "1.8.7 | PATCH | Ensure GDM disabling automatic mounting of removable media is not overridden | Make lock file" - ansible.builtin.template: - src: etc/dconf/db/00-automount_lock.j2 - dest: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/locks/00-automount_lock" - owner: root - group: root - mode: 'go-wx' - notify: Reload dconf + - name: "1.8.7 | PATCH | Ensure GDM disabling automatic mounting of removable media is not overridden | Make lock file" + ansible.builtin.template: + src: etc/dconf/db/00-automount_lock.j2 + dest: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/locks/00-automount_lock" + owner: root + group: root + mode: 0644 + notify: Reload dconf + when: + - rhel9cis_rule_1_8_7 + - rhel9cis_gui + tags: + - level1-server + - level2-workstation + - patch + - gui + - rule_1.8.7 - name: "1.8.8 | PATCH | Ensure GDM autorun-never is enabled" - when: - - rhel9cis_rule_1_8_8 - - rhel9cis_gui - tags: - - level1-server - - level2-workstation - - patch - - gui - - rule_1.8.8 block: - - name: "1.8.8 | PATCH | Ensure GDM autorun-never is enabled | Make directory" - ansible.builtin.file: - path: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d" - owner: root - group: root - mode: 'go-w' - state: directory + - name: "1.8.8 | PATCH | Ensure GDM autorun-never is enabled | Make directory" + ansible.builtin.file: + path: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d" + owner: root + group: root + mode: 0755 + state: directory - - name: "1.8.8 | PATCH | Ensure GDM autorun-never is enabled | Make conf file" - ansible.builtin.template: - src: etc/dconf/db/00-media-autorun.j2 - dest: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/00-media-autorun" - owner: root - group: root - mode: 'go-wx' - notify: Reload dconf + - name: "1.8.8 | PATCH | Ensure GDM autorun-never is enabled | Make conf file" + ansible.builtin.template: + src: etc/dconf/db/00-media-autorun.j2 + dest: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/00-media-autorun" + owner: root + group: root + mode: '0644' + notify: Reload dconf + when: + - rhel9cis_rule_1_8_8 + - rhel9cis_gui + tags: + - level1-server + - level2-workstation + - patch + - gui + - rule_1.8.8 - name: "1.8.9 | PATCH | Ensure GDM autorun-never is not overridden" - when: - - rhel9cis_rule_1_8_9 - - rhel9cis_gui - tags: - - level1-server - - level2-workstation - - patch - - gui - - rule_1.8.9 block: - - name: "1.8.9 | PATCH | Ensure GDM autorun-never is not overridden | Make lock directory" - ansible.builtin.file: - path: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/locks" - owner: root - group: root - mode: 'go-w' - state: directory + - name: "1.8.9 | PATCH | Ensure GDM autorun-never is not overridden | Make lock directory" + ansible.builtin.file: + path: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/locks" + owner: root + group: root + mode: 0755 + state: directory - - name: "1.8.9 | PATCH | Ensure GDM autorun-never is not overridden | Make lockfile" - ansible.builtin.template: - src: etc/dconf/db/00-autorun_lock.j2 - dest: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/locks/00-autorun_lock" - owner: root - group: root - mode: 'go-wx' - notify: Reload dconf + - name: "1.8.9 | PATCH | Ensure GDM autorun-never is not overridden | Make lockfile" + ansible.builtin.template: + src: etc/dconf/db/00-autorun_lock.j2 + dest: "/etc/dconf/db/{{ rhel9cis_dconf_db_name }}.d/locks/00-autorun_lock" + owner: root + group: root + mode: 0644 + notify: Reload dconf + when: + - rhel9cis_rule_1_8_9 + - rhel9cis_gui + tags: + - level1-server + - level2-workstation + - patch + - gui + - rule_1.8.9 - name: "1.8.10 | PATCH | Ensure XDMCP is not enabled" - when: - - rhel9cis_rule_1_8_10 - - rhel9cis_gui - tags: - - level1-server - - level1-workstation - - patch - - gui - - rule_1.8.10 ansible.builtin.lineinfile: - path: /etc/gdm/custom.conf - regexp: 'Enable=true' - state: absent + path: /etc/gdm/custom.conf + regexp: 'Enable=true' + state: absent + when: + - rhel9cis_rule_1_8_10 + - rhel9cis_gui + tags: + - level1-server + - level1-workstation + - patch + - gui + - rule_1.8.4 diff --git a/tasks/section_1/cis_1.9.yml b/tasks/section_1/cis_1.9.yml new file mode 100644 index 0000000..e226948 --- /dev/null +++ b/tasks/section_1/cis_1.9.yml @@ -0,0 +1,16 @@ +--- + +- name: "1.9 | PATCH | Ensure updates, patches, and additional security software are installed" + ansible.builtin.package: + name: "*" + state: latest + notify: Change_requires_reboot + when: + - rhel9cis_rule_1_9 + - not system_is_ec2 + tags: + - level1-server + - level1-workstation + - patch + - rule_1.9 + - skip_ansible_lint diff --git a/tasks/section_1/main.yml b/tasks/section_1/main.yml index fff557b..d9bc3b5 100644 --- a/tasks/section_1/main.yml +++ b/tasks/section_1/main.yml @@ -1,66 +1,59 @@ --- - name: "SECTION | 1.1.1.x | Disable unused filesystems" - ansible.builtin.import_tasks: - file: cis_1.1.1.x.yml + ansible.builtin.import_tasks: cis_1.1.1.x.yml -- name: "SECTION | 1.1.2.1.x | Configure /tmp" - ansible.builtin.import_tasks: - file: cis_1.1.2.1.x.yml +- name: "SECTION | 1.1.2.x | Configure /tmp" + ansible.builtin.import_tasks: cis_1.1.2.x.yml -- name: "SECTION | 1.1.2.2.x | Configure /dev/shm" - ansible.builtin.import_tasks: - file: cis_1.1.2.2.x.yml +- name: "SECTION | 1.1.3.x | Configure /var" + ansible.builtin.import_tasks: cis_1.1.3.x.yml -- name: "SECTION | 1.1.2.3.x | Configure /home" - ansible.builtin.import_tasks: - file: cis_1.1.2.3.x.yml +- name: "SECTION | 1.1.4.x | Configure /var/tmp" + ansible.builtin.import_tasks: cis_1.1.4.x.yml -- name: "SECTION | 1.1.2.4.x | Configure /var" - ansible.builtin.import_tasks: - file: cis_1.1.2.4.x.yml +- name: "SECTION | 1.1.5.x | Configure /var/log" + ansible.builtin.import_tasks: cis_1.1.5.x.yml -- name: "SECTION | 1.1.2.5.x | Configure /var/tmp" - ansible.builtin.import_tasks: - file: cis_1.1.2.5.x.yml +- name: "SECTION | 1.1.6.x | Configure /var/log/audit" + ansible.builtin.import_tasks: cis_1.1.6.x.yml -- name: "SECTION | 1.1.2.6.x | Configure /var/log" - ansible.builtin.import_tasks: - file: cis_1.1.2.6.x.yml +- name: "SECTION | 1.1.7.x | Configure /home" + ansible.builtin.import_tasks: cis_1.1.7.x.yml -- name: "SECTION | 1.1.2.7.x | Configure /var/log/audit" - ansible.builtin.import_tasks: - file: cis_1.1.2.7.x.yml +- name: "SECTION | 1.1.8.x | Configure /dev/shm" + ansible.builtin.import_tasks: cis_1.1.8.x.yml -- name: "SECTION | 1.2.1.x | Configure Package Repositories" - ansible.builtin.import_tasks: - file: cis_1.2.1.x.yml +- name: "SECTION | 1.1.x | Disable various mounting" + ansible.builtin.import_tasks: cis_1.1.x.yml -- name: "SECTION | 1.2.2.x | Configure Package Updates" - ansible.builtin.import_tasks: - file: cis_1.2.2.x.yml +- name: "SECTION | 1.2 | Configure Software Updates" + ansible.builtin.import_tasks: cis_1.2.x.yml -- name: "SECTION | 1.3.1 | Configure SELinux" - ansible.builtin.import_tasks: - file: cis_1.3.1.x.yml +- name: "SECTION | 1.3 | Filesystem Integrity Checking" + ansible.builtin.import_tasks: cis_1.3.x.yml + when: rhel9cis_config_aide -- name: "SECTION | 1.4 | Configure Bootloader" - ansible.builtin.import_tasks: - file: cis_1.4.x.yml +- name: "SECTION | 1.4 | Secure Boot Settings" + ansible.builtin.import_tasks: cis_1.4.x.yml - name: "SECTION | 1.5 | Additional Process Hardening" - ansible.builtin.import_tasks: - file: cis_1.5.x.yml + ansible.builtin.import_tasks: cis_1.5.x.yml -- name: "SECTION | 1.6 | Configure system wide crypto policy" - ansible.builtin.import_tasks: - file: cis_1.6.x.yml +- name: "SECTION | 1.6 | Mandatory Access Control" + include_tasks: cis_1.6.1.x.yml + when: not rhel9cis_selinux_disable - name: "SECTION | 1.7 | Command Line Warning Banners" - ansible.builtin.import_tasks: - file: cis_1.7.x.yml + ansible.builtin.import_tasks: cis_1.7.x.yml - name: "SECTION | 1.8 | Gnome Display Manager" - when: rhel9cis_display_manager == 'gdm' - ansible.builtin.import_tasks: - file: cis_1.8.x.yml + ansible.builtin.import_tasks: cis_1.8.x.yml + +- name: "SECTION | 1.9 | Updates and Patches" + ansible.builtin.import_tasks: cis_1.9.yml + +- name: "SECTION | 1.10 | Crypto policies" + include_tasks: cis_1.10.yml + when: + - not system_is_ec2 diff --git a/tasks/section_2/cis_2.1.x.yml b/tasks/section_2/cis_2.1.x.yml index 28e372d..43cc226 100644 --- a/tasks/section_2/cis_2.1.x.yml +++ b/tasks/section_2/cis_2.1.x.yml @@ -1,695 +1,40 @@ --- -- name: "2.1.1 | PATCH | Ensure autofs services are not in use" - when: - - rhel9cis_rule_2_1_1 - - "'autofs' in ansible_facts.packages" - tags: - - level1-server - - level2-workstation - - automated - - patch - - NIST800-53R5_SI-3 - - NIST800-53R5_MP-7 - - rule_2.1.1 - block: - - name: "2.1.1 | PATCH | Ensure autofs services are not in use | Remove Package" - when: - - not rhel9cis_autofs_services - - not rhel9cis_autofs_mask - ansible.builtin.package: - name: autofs - state: absent - - - name: "2.1.1 | PATCH | Ensure autofs services are not in use | Mask service" - when: - - not rhel9cis_autofs_services - - rhel9cis_autofs_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: autofs - enabled: false - state: stopped - masked: true - -- name: "2.1.2 | PATCH | Ensure avahi daemon services are not in use" - when: rhel9cis_rule_2_1_2 - tags: - - level1-server - - level2-workstation - - automated - - patch - - avahi - - NIST800-53R5_SI-4 - - rule_2.1.2 - block: - - name: "2.1.2 | PATCH | Ensure avahi daemon services are not in use | Remove package" - when: - - not rhel9cis_avahi_server - - not rhel9cis_avahi_mask - ansible.builtin.package: - name: - - avahi-autoipd - - avahi - state: absent - - - name: "2.1.2 | PATCH | Ensure avahi daemon services are not in use | Mask service" - when: - - not rhel9cis_avahi_server - - rhel9cis_avahi_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: "{{ item }}" - enabled: false - state: stopped - masked: true - loop: - - avahi-daemon.socket - - avahi-daemon.service - -- name: "2.1.3 | PATCH | Ensure dhcp server services are not in use" - when: rhel9cis_rule_2_1_3 - tags: - - level1-server - - level1-workstation - - automated - - patch - - dhcp - - NIST800-53R5_CM-7 - - rule_2.1.3 - block: - - name: "2.1.3 | PATCH | Ensure dhcp server services are not in use | Remove package" - when: - - not rhel9cis_dhcp_server - - not rhel9cis_dhcp_mask - ansible.builtin.package: - name: dhcp-server - state: absent - - - name: "2.1.3 | PATCH | Ensure dhcp server services are not in use | Mask service" - when: - - not rhel9cis_dhcp_server - - rhel9cis_dhcp_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: "{{ item }}" - enabled: false - state: stopped - masked: true - loop: - - dhcpd.service - - dhcpd6.service - -- name: "2.1.4 | PATCH | Ensure dns server services are not in use" - when: rhel9cis_rule_2_1_4 - tags: - - level1-server - - level1-workstation - - automated - - patch - - dns - - NIST800-53R5_CM-7 - - rule_2.1.4 - block: - - name: "2.1.4 | PATCH | Ensure dns server services are not in use | Remove package" - when: - - not rhel9cis_dns_server - - not rhel9cis_dns_mask - ansible.builtin.package: - name: bind - state: absent - - - name: "2.1.4 | PATCH | Ensure dns server services are not in use | Mask service" - when: - - not rhel9cis_dns_server - - rhel9cis_dns_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: named.service - enabled: false - state: stopped - masked: true - -- name: "2.1.5 | PATCH | Ensure dnsmasq server services are not in use" - when: rhel9cis_rule_2_1_5 - tags: - - level1-server - - level1-workstation - - automated - - patch - - dns - - NIST800-53R5_CM-7 - - rule_2.1.5 - block: - - name: "2.1.5 | PATCH | Ensure dnsmasq server services are not in use | Remove package" - when: - - not rhel9cis_dnsmasq_server - - not rhel9cis_dnsmasq_mask - ansible.builtin.package: - name: dnsmasq - state: absent - - - name: "2.1.5 | PATCH | Ensure dnsmasq server services are not in use | Mask service" - when: - - not rhel9cis_dnsmasq_server - - rhel9cis_dnsmasq_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: dnsmasq.service - enabled: false - state: stopped - masked: true - -- name: "2.1.6 | PATCH | Ensure samba file server services are not in use" - when: rhel9cis_rule_2_1_6 - tags: - - level1-server - - level1-workstation - - automated - - patch - - samba - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - rule_2.1.6 - block: - - name: "2.1.6 | PATCH | Ensure samba file server services are not in use | Remove package" - when: - - not rhel9cis_samba_server - - not rhel9cis_samba_mask - ansible.builtin.package: - name: samba - state: absent - - - name: "2.1.6 | PATCH | Ensure samba file server services are not in use | Mask service" - when: - - not rhel9cis_samba_server - - rhel9cis_samba_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: smb.service - enabled: false - state: stopped - masked: true - -- name: "2.1.7 | PATCH | Ensure ftp server services are not in use" - when: rhel9cis_rule_2_1_7 - tags: - - level1-server - - level1-workstation - - automation - - patch - - ftp - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - rule_2.1.7 - block: - - name: "2.1.7 | PATCH | Ensure ftp server services are not in use | Remove package" - when: - - not rhel9cis_ftp_server - - not rhel9cis_ftp_mask - ansible.builtin.package: - name: vsftpd - state: absent - - - name: "2.1.7 | PATCH | Ensure ftp server services are not in use | Mask service" - when: - - not rhel9cis_ftp_server - - rhel9cis_ftp_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: vsftpd.service - enabled: false - state: stopped - masked: true - -- name: "2.1.8 | PATCH | Ensure message access server services are not in use" - when: rhel9cis_rule_2_1_8 - tags: - - level1-server - - level1-workstation - - automated - - patch - - dovecot - - imap - - pop3 - - NIST800-53R5_CM-7 - - rule_2.1.8 - block: - - name: "2.1.8 | PATCH | Ensure message access server services are not in use | Remove package" - when: - - not rhel9cis_message_server - - not rhel9cis_message_mask - ansible.builtin.package: - name: - - dovecot - - cyrus-imapd - state: absent - - - name: "2.1.8 | PATCH | Ensure message access server services are not in use | Mask service" - when: - - not rhel9cis_message_server - - rhel9cis_message_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: "{{ item }}" - enabled: false - state: stopped - masked: true - loop: - - "dovecot.socket" - - "dovecot.service" - - "cyrus-imapd.service" - -- name: "2.1.9 | PATCH | Ensure network file system services are not in use" - when: rhel9cis_rule_2_1_9 - tags: - - level1-server - - level1-workstation - - automated - - patch - - nfs - - services - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - rule_2.1.9 - block: - - name: "2.1.9 | PATCH | Ensure network file system services are not in use | Remove package" - when: - - not rhel9cis_nfs_server - - not rhel9cis_nfs_mask - ansible.builtin.package: - name: nfs-utils - state: absent - - - name: "2.1.9 | PATCH | Ensure network file system services are not in use | Mask service" - when: - - not rhel9cis_nfs_server - - rhel9cis_nfs_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: nfs-server.service - enabled: false - state: stopped - masked: true - -- name: "2.1.10 | PATCH | Ensure nis server services are not in use" - when: rhel9cis_rule_2_1_10 - tags: - - level1-server - - level1-workstation - - automated - - patch - - nis - - NIST800-53R5_CM-7 - - rule_2.1.10 - notify: Systemd daemon reload - block: - - name: "2.1.10 | PATCH | Ensure nis server services are not in use | Remove package" - when: - - not rhel9cis_nis_server - - not rhel9cis_nis_mask - ansible.builtin.package: - name: ypserv - state: absent - - - name: "2.1.10 | PATCH | Ensure nis server services are not in use | Mask service" - when: - - not rhel9cis_nis_server - - rhel9cis_nis_mask - ansible.builtin.systemd: - name: ypserv.service - enabled: false - state: stopped - masked: true - -- name: "2.1.11 | PATCH | Ensure print server services are not in use" - when: rhel9cis_rule_2_1_11 - tags: - - level1-server - - automated - - patch - - cups - - NIST800-53R5_CM-7 - - rule_2.1.11 - block: - - name: "2.1.11 | PATCH | Ensure print server services are not in use | Remove package" - when: - - not rhel9cis_print_server - - not rhel9cis_print_mask - ansible.builtin.package: - name: cups - state: absent - - - name: "2.1.11 | PATCH | Ensure print server services are not in use | Mask service" - when: - - not rhel9cis_print_server - - rhel9cis_print_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: "{{ item }}" - enabled: false - state: stopped - masked: true - loop: - - "cups.socket" - - "cups.service" - -- name: "2.1.12 | PATCH | Ensure rpcbind services are not in use" - when: rhel9cis_rule_2_1_12 - tags: - - level1-server - - level1-workstation - - automated - - patch - - rpc - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - rule_2.1.12 - block: - - name: "2.1.12 | PATCH | Ensure rpcbind services are not in use | Remove package" - when: - - not rhel9cis_rpc_server - - not rhel9cis_rpc_mask - ansible.builtin.package: - name: rpcbind - state: absent - - - name: "2.1.12 | PATCH | Ensure rpcbind services are not in use | Mask service" - when: - - not rhel9cis_rpc_server - - rhel9cis_rpc_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: "{{ item }}" - enabled: false - state: stopped - masked: true - loop: - - rpcbind.service - - rpcbind.socket - -- name: "2.1.13 | PATCH | Ensure rsync services are not in use" - when: rhel9cis_rule_2_1_13 - tags: - - level1-server - - level1-workstation - - automated - - patch - - rsync - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - rule_2.1.13 - block: - - name: "2.1.13 | PATCH | Ensure rsync services are not in use | Remove package" - when: - - not rhel9cis_rsync_server - - not rhel9cis_rsync_mask - ansible.builtin.package: - name: rsync-daemon - state: absent - - - name: "2.1.13 | PATCH | Ensure rsync services are not in use | Mask service" - when: - - not rhel9cis_rsync_server - - rhel9cis_rsync_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: "{{ item }}" - enabled: false - state: stopped - masked: true - loop: - - 'rsyncd.socket' - - 'rsyncd.service' - -- name: "2.1.14 | PATCH | Ensure snmp services are not in use" - when: rhel9cis_rule_2_1_14 - tags: - - level1-server - - level1-workstation - - automation - - patch - - snmp - - NIST800-53R5_CM-7 - - rule_2.1.14 - block: - - name: "2.1.14 | PATCH | Ensure snmp services are not in use | Remove package" - when: - - not rhel9cis_snmp_server - - not rhel9cis_snmp_mask - ansible.builtin.package: - name: net-snmp - state: absent - - - name: "2.1.14 | PATCH | Ensure snmp services are not in use | Mask service" - when: - - not rhel9cis_snmp_server - - rhel9cis_snmp_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: snmpd.service - enabled: false - state: stopped - masked: true - -- name: "2.1.15 | PATCH | Ensure telnet server services are not in use" - when: rhel9cis_rule_2_1_15 - tags: - - level1-server - - level1-workstation - - automated - - patch - - telnet - - NIST800-53R5_CM-7 - - NIST800-53R5_CM-11 - - rule_2.1.15 - block: - - name: "2.1.15 | PATCH | Ensure telnet server services are not in use | Remove package" - when: - - not rhel9cis_telnet_server - - not rhel9cis_telnet_mask - ansible.builtin.package: - name: telnet-server - state: absent - - - name: "2.1.15 | PATCH | Ensure telnet server services are not in use | Mask service" - when: - - not rhel9cis_telnet_server - - rhel9cis_telnet_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: telnet.socket - enabled: false - state: stopped - masked: true - -- name: "2.1.16 | PATCH | Ensure tftp server services are not in use" - when: rhel9cis_rule_2_1_16 - tags: - - level1-server - - level1-workstation - - automated - - patch - - tftp - - NIST800-53R5_CM-7 - - rule_2.1.16 - block: - - name: "2.1.16 | PATCH | Ensure tftp server services are not in use | Remove package" - when: - - not rhel9cis_tftp_server - - not rhel9cis_tftp_mask - ansible.builtin.package: - name: tftp-server - state: absent - - - name: "2.1.16 | PATCH | Ensure tftp server services are not in use | Mask service" - when: - - not rhel9cis_tftp_server - - rhel9cis_tftp_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: "{{ item }}" - enabled: false - state: stopped - masked: true - loop: - - 'tftp.socket' - - 'tftp.service' - -- name: "2.1.17 | PATCH | Ensure web proxy server services are not in use" - when: rhel9cis_rule_2_1_17 - tags: - - level1-server - - level1-workstation - - automation - - patch - - squid - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - rule_2.1.17 - block: - - name: "2.1.17 | PATCH | Ensure web proxy server services are not in use | Remove package" - when: - - not rhel9cis_squid_server - - not rhel9cis_squid_mask - ansible.builtin.package: - name: squid - state: absent - - - name: "2.1.17 | PATCH | Ensure web proxy server services are not in use | Mask service" - when: - - not rhel9cis_squid_server - - rhel9cis_squid_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: squid.service - enabled: false - state: stopped - masked: true - -- name: "2.1.18 | PATCH | Ensure web server services are not in use" - when: rhel9cis_rule_2_1_18 - tags: - - level1-server - - level1-workstation - - automated - - patch - - httpd - - nginx - - webserver - - NIST800-53R5_CM-7 - - rule_2.1.18 - block: - - name: "2.1.18 | PATCH | Ensure web server services are not in use | Remove httpd server" - when: - - not rhel9cis_httpd_server - - not rhel9cis_httpd_mask - ansible.builtin.package: - name: httpd - state: absent - - - name: "2.1.18 | PATCH | Ensure web server services are not in use | Remove nginx server" - when: - - not rhel9cis_nginx_server - - not rhel9cis_nginx_mask - ansible.builtin.package: - name: nginx - state: absent - - - name: "2.1.18 | PATCH | Ensure web server services are not in use | Mask httpd service" - when: - - not rhel9cis_httpd_server - - rhel9cis_httpd_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: httpd.service - enabled: false - state: stopped - masked: true - - - name: "2.1.18 | PATCH | Ensure web server services are not in use | Mask nginx service" - when: - - not rhel9cis_nginx_server - - rhel9cis_nginx_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: ngnix.service - enabled: false - state: stopped - masked: true - -- name: "2.1.19 | PATCH | Ensure xinetd services are not in use" - when: rhel9cis_rule_2_1_19 - tags: - - level1-server - - level1-workstation - - automated - - patch - - xinetd - - NIST800-53R5_CM-7 - - rule_2.1.19 - block: - - name: "2.1.19 | PATCH | Ensure xinetd services are not in use | Remove package" - when: - - not rhel9cis_xinetd_server - - not rhel9cis_xinetd_mask - ansible.builtin.package: - name: xinetd - state: absent - - - name: "2.1.19 | PATCH | Ensure xinetd services are not in use | Mask service" - when: - - not rhel9cis_xinetd_server - - rhel9cis_xinetd_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: xinetd.service - enabled: false - state: stopped - masked: true - -- name: "2.1.20 | PATCH | Ensure X window server services are not in use" - when: - - not rhel9cis_xwindow_server - - rhel9cis_rule_2_1_20 - tags: - - level1-server - - level1-workstation - - automated - - patch - - xwindow - - NIST800-53R5_CM-11 - - rule_2.1.20 +- name: "2.1.1 | PATCH | Ensure time synchronization is in use" ansible.builtin.package: - name: xorg-x11-server-common - state: absent - -- name: "2.1.21 | PATCH | Ensure mail transfer agents are configured for local-only mode" + name: chrony + state: present when: - - not rhel9cis_is_mail_server - - "'postfix' in ansible_facts.packages" - - rhel9cis_rule_2_1_21 + - rhel9cis_rule_2_1_1 + - not system_is_container tags: - - level1-server - - level1-workstation - - automated - - patch - - postfix - - NIST800-53R5_CM-7 - - rule_2.1.21 - notify: Restart postfix - ansible.builtin.lineinfile: - path: /etc/postfix/main.cf - regexp: "^(#)?inet_interfaces" - line: "inet_interfaces = loopback-only" + - level1-server + - level1-workstation + - patch + - rule_2.1.1 -- name: "2.1.22 | AUDIT | Ensure only approved services are listening on a network interface" - when: rhel9cis_rule_2_1_22 - tags: - - level1-server - - level1-workstation - - manual - - audit - - services - - NIST800-53R5_CM-7 - - rule_2.1.22 - vars: - warn_control_id: '2.1.22' +- name: "2.1.2 | PATCH | Ensure chrony is configured" block: - - name: "2.1.22 | AUDIT | Ensure only approved services are listening on a network interface | Get list of services" - ansible.builtin.command: systemctl list-units --type=service # noqa command-instead-of-module - changed_when: false - failed_when: discovered_running_services.rc not in [ 0, 1 ] - check_mode: false - register: discovered_running_services + - name: "2.1.2 | PATCH | Ensure chrony is configured | Set configuration" + ansible.builtin.template: + src: etc/chrony.conf.j2 + dest: /etc/chrony.conf + owner: root + group: root + mode: 0644 - - name: "2.1.22 | AUDIT | Ensure only approved services are listening on a network interface | Display list of services" - ansible.builtin.debug: - msg: - - "Warning!! Below are the list of services, both active and inactive" - - "Please review to make sure all are essential" - - "{{ discovered_running_services.stdout_lines }}" - - - name: "2.1.22 | AUDIT | Ensure only approved services are listening on a network interface | Warn Count" - ansible.builtin.import_tasks: - file: warning_facts.yml + - name: "2.1.2 | PATCH | Ensure chrony is configured | modify /etc/sysconfig/chronyd | 1" + ansible.builtin.lineinfile: + path: /etc/sysconfig/chronyd + regexp: "^(#)?OPTIONS" + line: "OPTIONS=\"-u chrony\"" + create: true + mode: 0644 + when: + - rhel9cis_rule_2_1_2 + - not system_is_container + tags: + - level1-server + - level1-workstation + - patch + - rule_2.1.2 diff --git a/tasks/section_2/cis_2.2.x.yml b/tasks/section_2/cis_2.2.x.yml index 0e019e7..e592d17 100644 --- a/tasks/section_2/cis_2.2.x.yml +++ b/tasks/section_2/cis_2.2.x.yml @@ -1,81 +1,349 @@ --- -- name: "2.2.1 | PATCH | Ensure ftp client is not installed" - when: - - not rhel9cis_ftp_client - - rhel9cis_rule_2_2_1 - tags: - - level1-server - - level1-workstation - - automated - - patch - - ftp - - NIST800-53R5_CM-7 - - rule_2.2.1 +- name: "2.2.1 | PATCH | Ensure xorg-x11-server-common is not installed" ansible.builtin.package: - name: ftp - state: absent + name: xorg-x11-server-common + state: absent + when: + - rhel9cis_rule_2_2_1 + - "'xorg-x11-server-common' in ansible_facts.packages" + - not rhel9cis_gui + tags: + - level1-server + - patch + - x11 + - rule_2.2.1 -- name: "2.2.2 | PATCH | Ensure ldap client is not installed" - when: - - not rhel9cis_openldap_clients_required - - rhel9cis_rule_2_2_2 - tags: - - level2-server - - level2-workstation - - automated - - patch - - ldap - - NIST800-53R5_CM-7 - - rule_2.2.2 +- name: "2.2.2 | PATCH | Ensure Avahi Server is not installed" ansible.builtin.package: - name: openldap-clients - state: absent + name: + - avahi-autoipd + - avahi + state: absent + when: + - rhel9cis_rule_2_2_2 + - not rhel9cis_avahi_server + - "'avahi' in ansible_facts.packages or 'avahi-autopd' in ansible_facts.packages" + tags: + - level1-server + - level2-workstation + - patch + - avahi + - rule_2.2.2 -- name: "2.2.3 | PATCH | Ensure nis client is not installed" - when: - - not rhel9cis_ypbind_required - - rhel9cis_rule_2_2_3 - tags: - - level1-server - - level1-workstation - - automated - - patch - - nis - - NIST800-53R5_CM-7 - - rule_2.2.3 +- name: "2.2.3 | PATCH | Ensure CUPS is not installed" ansible.builtin.package: - name: ypbind - state: absent + name: cups + state: absent + when: + - not rhel9cis_cups_server + - "'cups' in ansible_facts.packages" + - rhel9cis_rule_2_2_3 + tags: + - level1-server + - patch + - cups + - rule_2.2.3 -- name: "2.2.4 | PATCH | Ensure telnet client is not installed" - when: - - not rhel9cis_telnet_required - - rhel9cis_rule_2_2_4 - tags: - - level1-server - - level1-workstation - - automated - - patch - - telnet - - NIST800-53R5_CM-7 - - rule_2.2.4 +- name: "2.2.4 | PATCH | Ensure DHCP Server is not installed" ansible.builtin.package: - name: telnet - state: absent + name: dhcp-server + state: absent + when: + - not rhel9cis_dhcp_server + - "'dhcp-server' in ansible_facts.packages" + - rhel9cis_rule_2_2_4 + tags: + - level1-server + - level1-workstation + - patch + - dhcp + - rule_2.2.4 -- name: "2.2.5 | PATCH | Ensure TFTP client is not installed" - when: - - not rhel9cis_tftp_client - - rhel9cis_rule_2_2_5 - tags: - - level1-server - - level1-workstation - - automated - - patch - - tftp - - NIST800-53R5_CM-7 - - rule_2.2.5 +- name: "2.2.5 | PATCH | Ensure DNS Server is not installed" ansible.builtin.package: - name: tftp - state: absent + name: bind + state: absent + when: + - not rhel9cis_dns_server + - "'bind' in ansible_facts.packages" + - rhel9cis_rule_2_2_5 + tags: + - level1-server + - level1-workstation + - patch + - dns + - rule_2.2.5 + +- name: "2.2.6 | PATCH | Ensure VSFTP Server is not installed" + ansible.builtin.package: + name: vsftpd + state: absent + when: + - not rhel9cis_vsftpd_server + - "'vsftpd' in ansible_facts.packages" + - rhel9cis_rule_2_2_6 + tags: + - level1-server + - level1-workstation + - patch + - vsftpd + - rule_2.2.6 + +- name: "2.2.7 | PACH | Ensure TFTP Server is not installed" + ansible.builtin.package: + name: tftp-server + state: absent + when: + - not rhel9cis_tftp_server + - "'tftp-server' in ansible_facts.packages" + - rhel9cis_rule_2_2_7 + tags: + - level1-server + - level1-workstation + - patch + - tftp + - rule_2.2.7 + +- name: "2.2.8 | PATCH | Ensure a web server is not installed" + block: + - name: "2.2.8 | PATCH | Ensure a web server is not installed | Remove httpd server" + ansible.builtin.package: + name: httpd + state: absent + when: + - not rhel9cis_httpd_server + - "'httpd' in ansible_facts.packages" + + - name: "2.2.8 | PATCH | Ensure a web server is not installed | Remove nginx server" + ansible.builtin.package: + name: nginx + state: absent + when: + - not rhel9cis_nginx_server + - "'nginx' in ansible_facts.packages" + when: + - rhel9cis_rule_2_2_8 + tags: + - level1-server + - level1-workstation + - patch + - httpd + - nginx + - webserver + - rule_2.2.8 + +- name: "2.2.9 | PATCH | Ensure IMAP and POP3 server is not installed" + block: + - name: "2.2.9 | PATCH | Ensure IMAP and POP3 server is not installed" + ansible.builtin.package: + name: + - dovecot + state: absent + when: + - not rhel9cis_dovecot_server + - "'dovecot' in ansible_facts.packages" + + - name: "2.2.9 | PATCH | Ensure IMAP and POP3 server is not installed" + ansible.builtin.package: + name: + - cyrus-imapd + state: absent + when: + - not rhel9cis_imap_server + - "'cyrus-imapd' in ansible_facts.packages" + + when: + - rhel9cis_rule_2_2_9 + tags: + - level1-server + - level1-workstation + - patch + - dovecot + - imap + - pop3 + - rule_2.2.9 + +- name: "2.2.10 | PATCH | Ensure Samba is not enabled" + ansible.builtin.package: + name: samba + state: absent + when: + - not rhel9cis_samba_server + - "'samba' in ansible_facts.packages" + - rhel9cis_rule_2_2_10 + tags: + - level1-server + - level1-workstation + - patch + - samba + - rule_2.2.10 + +- name: "2.2.11 | PATCH | Ensure HTTP Proxy Server is not installed" + ansible.builtin.package: + name: squid + state: absent + when: + - not rhel9cis_squid_server + - "'squid' in ansible_facts.packages" + - rhel9cis_rule_2_2_11 + tags: + - level1-server + - level1-workstation + - patch + - squid + - rule_2.2.11 + +- name: "2.2.12 | PATCH | Ensure net-snmp is not installed" + ansible.builtin.package: + name: net-snmp + state: absent + when: + - not rhel9cis_snmp_server + - "'net-snmp' in ansible_facts.packages" + - rhel9cis_rule_2_2_12 + tags: + - level1-server + - level1-workstation + - patch + - snmp + - rule_2.2.12 + +- name: "2.2.13 | PATCH | Ensure telnet-server is not installed" + ansible.builtin.package: + name: telnet-server + state: absent + when: + - not rhel9cis_telnet_server + - "'telnet-server' in ansible_facts.packages" + - rhel9cis_rule_2_2_13 + tags: + - level1-server + - level1-workstation + - patch + - telnet + - rule_2.2.13 + +- name: "2.2.14 | PATCH | Ensure dnsmasq is not installed" + ansible.builtin.package: + name: dnsmasq + state: absent + notify: Restart postfix + when: + - not rhel9cis_is_mail_server + - "'dnsmasq' in ansible_facts.packages" + - rhel9cis_rule_2_2_14 + tags: + - level1-server + - level1-workstation + - patch + - dnsmasq + - rule_2.2.14 + +- name: "2.2.15 | PATCH | Ensure mail transfer agent is configured for local-only mode" + ansible.builtin.lineinfile: + path: /etc/postfix/main.cf + regexp: "^(#)?inet_interfaces" + line: "inet_interfaces = loopback-only" + notify: Restart postfix + when: + - not rhel9cis_is_mail_server + - "'postfix' in ansible_facts.packages" + - rhel9cis_rule_2_2_15 + tags: + - level1-server + - level1-workstation + - patch + - postfix + - rule_2.2.15 + +# The name title of the service says mask the service, but the fix allows for both options +# Options available in default/main if to remove the package default is false just mask the server service +- name: "2.2.16 | PATCH | Ensure nfs-utils is not installed or the nfs-server service is masked" + block: + - name: "2.2.16 | PATCH | Ensure nfs-utils is not installed or the nfs-server service is masked | remove package" + ansible.builtin.package: + name: nfs-utils + state: absent + when: + - not rhel9cis_use_nfs_server + - not rhel9cis_use_nfs_service + + - name: "2.2.16 | PATCH | Ensure nfs-utils is not installed or the nfs-server service is masked | mask service" + ansible.builtin.systemd: + name: nfs-server + masked: true + state: stopped + when: + - not rhel9cis_use_nfs_server + - rhel9cis_use_nfs_service + when: + - "'nfs-utils' in ansible_facts.packages" + - rhel9cis_rule_2_2_16 + tags: + - level1-server + - level1-workstation + - patch + - nfs + - services + - rule_2.2.16 + +# The name title of the service says mask the service, but the fix allows for both options +# Options available in default/main if to remove the package default is false just mask the server service +- name: "2.2.17 | PATCH | Ensure rpcbind is not installed or the rpcbind services are masked" + block: + - name: "2.2.17 | PATCH | Ensure rpcbind is not installed or the rpcbind services are masked | remove package" + ansible.builtin.package: + name: rpcbind + state: absent + when: + - not rhel9cis_use_rpc_server + - not rhel9cis_use_rpc_service + + - name: "2.2.17 | PATCH | Ensure rpcbind is not installed or the rpcbind services are masked | mask service" + ansible.builtin.systemd: + name: rpcbind.socket + masked: true + state: stopped + when: + - rhel9cis_use_rpc_server + - not rhel9cis_use_rpc_service + when: + - "'rpcbind' in ansible_facts.packages" + - rhel9cis_rule_2_2_17 + tags: + - level1-server + - level1-workstation + - patch + - rpc + - rule_2.2.17 + +# The name title of the service says mask the service, but the fix allows for both options +# Options available in default/main if to remove the package default is false just mask the server service +- name: "2.2.18 | PATCH | Ensure rsync service is not enabled " + block: + - name: "2.2.18 | PATCH | Ensure rsync-daemon is not installed or the rsync service is masked | remove package" + ansible.builtin.package: + name: rsync-daemon + state: absent + when: + - not rhel9cis_use_rsync_server + - not rhel9cis_use_rsync_service + + - name: "2.2.18 | PATCH | Ensure rsync service is not enabled | mask service" + ansible.builtin.systemd: + name: rsyncd + masked: true + state: stopped + when: + - rhel9cis_use_rsync_server + - not rhel9cis_use_rsync_service + when: + - "'rsync' in ansible_facts.packages" + - rhel9cis_rule_2_2_18 + tags: + - level1-server + - level1-workstation + - patch + - rsync + - rule_2.2.18 diff --git a/tasks/section_2/cis_2.3.x.yml b/tasks/section_2/cis_2.3.x.yml index b84a84b..10a0662 100644 --- a/tasks/section_2/cis_2.3.x.yml +++ b/tasks/section_2/cis_2.3.x.yml @@ -1,51 +1,61 @@ --- -- name: "2.3.1 | PATCH | Ensure time synchronization is in use" - when: - - rhel9cis_rule_2_3_1 - - not system_is_container - tags: - - level1-server - - level1-workstation - - patch - - NIST800-53R5_AU-3 - - NIST800-53R5_AU-12 - - rule_2.3.1 +- name: "2.3.1 | PATCH | Ensure telnet client is not installed" ansible.builtin.package: - name: chrony - state: present - -- name: "2.3.2 | PATCH | Ensure chrony is configured" + name: telnet + state: absent when: - - rhel9cis_rule_2_3_2 - - not system_is_container + - not rhel9cis_telnet_required + - "'telnet' in ansible_facts.packages" + - rhel9cis_rule_2_3_1 tags: - - level1-server - - level1-workstation - - patch - - rule_2.3.2 - - NIST800-53R5_AU-3 - - NIST800-53R5_AU-12 - ansible.builtin.template: - src: etc/chrony.conf.j2 - dest: /etc/chrony.conf - owner: root - group: root - mode: 'go-wx' + - level1-server + - level1-workstation + - patch + - telnet + - rule_2.3.1 -- name: "2.3.3 | PATCH | Ensure chrony is not run as the root user" +- name: "2.3.2 | PATCH | Ensure LDAP client is not installed" + ansible.builtin.package: + name: openldap-clients + state: absent when: - - rhel9cis_rule_2_3_3 - - not system_is_container + - not rhel9cis_openldap_clients_required + - "'openldap-clients' in ansible_facts.packages" + - rhel9cis_rule_2_3_2 tags: - - level1-server - - level1-workstation - - patch - - rule_2.3.3 - ansible.builtin.lineinfile: - path: /etc/sysconfig/chronyd - regexp: '^OPTIONS="(?!.* -u chrony.*)(.*)"' - line: OPTIONS="\1 -u chrony" - create: true - backrefs: true - mode: 'go-wx' + - level1-server + - level1-workstation + - patch + - ldap + - rule_2.3.2 + +- name: "2.3.3 | PATCH | Ensure TFTP client is not installed" + ansible.builtin.package: + name: tftp + state: absent + when: + - not rhel9cis_tftp_client + - "'tftp' in ansible_facts.packages" + - rhel9cis_rule_2_3_3 + tags: + - level1-server + - level1-workstation + - patch + - tftp + - rule_2.3.3 + +- name: "2.3.4 | PATCH | Ensure FTP client is not installed" + ansible.builtin.package: + name: ftp + state: absent + when: + - not rhel9cis_tftp_client + - "'ftp' in ansible_facts.packages" + - rhel9cis_rule_2_3_4 + tags: + - level1-server + - level1-workstation + - patch + - ftp + - rule_2.3.4 diff --git a/tasks/section_2/cis_2.4.x.yml b/tasks/section_2/cis_2.4.x.yml deleted file mode 100644 index c4b6b8b..0000000 --- a/tasks/section_2/cis_2.4.x.yml +++ /dev/null @@ -1,173 +0,0 @@ ---- - -- name: "2.4.1.1 | PATCH | Ensure cron daemon is enabled" - when: rhel9cis_rule_2_4_1_1 - tags: - - level1-server - - level1-workstation - - patch - - cron - - rule_2.4.1.1 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - ansible.builtin.service: - name: crond - enabled: true - -- name: "2.4.1.2 | PATCH | Ensure permissions on /etc/crontab are configured" - when: rhel9cis_rule_2_4_1_2 - tags: - - level1-server - - level1-workstation - - patch - - cron - - rule_2.4.1.2 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/crontab - owner: root - group: root - mode: 'og-rwx' - -- name: "2.4.1.3 | PATCH | Ensure permissions on /etc/cron.hourly are configured" - when: rhel9cis_rule_2_4_1_3 - tags: - - level1-server - - level1-workstation - - patch - - cron - - rule_2.4.1.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/cron.hourly - state: directory - owner: root - group: root - mode: 'og-rwx' - -- name: "2.4.1.4 | PATCH | Ensure permissions on /etc/cron.daily are configured" - when: rhel9cis_rule_2_4_1_4 - tags: - - level1-server - - level1-workstation - - patch - - cron - - rule_2.4.1.4 - ansible.builtin.file: - path: /etc/cron.daily - state: directory - owner: root - group: root - mode: 'og-rwx' - -- name: "2.4.1.5 | PATCH | Ensure permissions on /etc/cron.weekly are configured" - when: rhel9cis_rule_2_4_1_5 - tags: - - level1-server - - level1-workstation - - patch - - rule_2.4.1.5 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/cron.weekly - state: directory - owner: root - group: root - mode: 'og-rwx' - -- name: "2.4.1.6 | PATCH | Ensure permissions on /etc/cron.monthly are configured" - when: rhel9cis_rule_2_4_1_6 - tags: - - level1-server - - level1-workstation - - patch - - rule_2.4.1.6 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/cron.monthly - state: directory - owner: root - group: root - mode: 'og-rwx' - -- name: "2.4.1.7 | PATCH | Ensure permissions on /etc/cron.d are configured" - when: rhel9cis_rule_2_4_1_7 - tags: - - level1-server - - level1-workstation - - patch - - cron - - rule_2.4.1.7 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/cron.d - state: directory - owner: root - group: root - mode: 'og-rwx' - -- name: "2.4.1.8 | PATCH | Ensure crontab is restricted to authorized users" - when: rhel9cis_rule_2_4_1_8 - tags: - - level1-server - - level1-workstation - - patch - - cron - - rule_2.4.1.8 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - block: - - name: "2.4.1.8 | PATCH | Ensure crontab is restricted to authorized users | Remove cron.deny" - ansible.builtin.file: - path: /etc/cron.deny - state: absent - - - name: "2.4.1.8 | PATCH | Ensure crontab is restricted to authorized users | Check if cron.allow exists" - ansible.builtin.stat: - path: "/etc/cron.allow" - register: discovered_cron_allow_state - - - name: "2.4.1.8 | PATCH | Ensure crontab is restricted to authorized users | Ensure cron.allow is restricted to authorized users" - ansible.builtin.file: - path: /etc/cron.allow - state: '{{ "file" if discovered_cron_allow_state.stat.exists else "touch" }}' - owner: root - group: root - mode: 'u-x,g-wx,o-rwx' - -- name: "2.4.2.1 | PATCH | Ensure at is restricted to authorized users" - when: rhel9cis_rule_2_4_2_1 - tags: - - level1-server - - level1-workstation - - patch - - cron - - rule_2.4.2.1 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - block: - - name: "2.4.2.1 | PATCH | Ensure at is restricted to authorized users | Remove at.deny" - ansible.builtin.file: - path: /etc/at.deny - state: absent - - - name: "2.4.2.1 | PATCH | Ensure at is restricted to authorized users | Check if at.allow exists" - ansible.builtin.stat: - path: "/etc/at.allow" - register: discovered_at_allow_state - - - name: "2.4.2.1 | PATCH | Ensure at is restricted to authorized users | Ensure at.allow is restricted to authorized users" - ansible.builtin.file: - path: /etc/at.allow - state: '{{ "file" if discovered_at_allow_state.stat.exists else "touch" }}' - owner: root - group: root - mode: 'u-x,g-wx,o-rwx' diff --git a/tasks/section_2/cis_2.4.yml b/tasks/section_2/cis_2.4.yml new file mode 100644 index 0000000..ce02b40 --- /dev/null +++ b/tasks/section_2/cis_2.4.yml @@ -0,0 +1,39 @@ +--- + +- name: "2.4 | AUDIT | Ensure nonessential services listening on the system are removed or masked" + block: + - name: "2.4 | AUDIT | Ensure nonessential services listening on the system are removed or masked | Get list of services" + ansible.builtin.shell: systemctl list-units --type=service + changed_when: false + failed_when: false + check_mode: false + register: rhel9cis_2_4_services + + - name: "2.4 | AUDIT | Ensure nonessential services listening on the system are removed or masked | Get list of sockets" + ansible.builtin.shell: systemctl list-units --type=sockets + changed_when: false + failed_when: false + check_mode: false + register: rhel9cis_2_4_sockets + + - name: "2.4 | AUDIT | Ensure nonessential services listening on the system are removed or masked | Display list of services" + ansible.builtin.debug: + msg: + - "Warning!! Below are the list of services and sockets, both active and inactive" + - "Please review to make sure all are essential" + - "{{ rhel9cis_2_4_services.stdout_lines }}" + - "{{ rhel9cis_2_4_sockets.stdout_lines }}" + + - name: "2.4 | AUDIT | Ensure nonessential services listening on the system are removed or masked | Warn Count" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '2.4' + when: + - rhel9cis_rule_2_4 + tags: + - level1-server + - level1-workstation + - manual + - audit + - services + - rule_2.4 diff --git a/tasks/section_2/main.yml b/tasks/section_2/main.yml index 6e373fa..39b912d 100644 --- a/tasks/section_2/main.yml +++ b/tasks/section_2/main.yml @@ -1,17 +1,13 @@ --- -- name: "SECTION | 2.1 | Special Purpose Services" - ansible.builtin.import_tasks: - file: cis_2.1.x.yml +- name: "SECTION | 2.1 | Time Synchronization" + ansible.builtin.import_tasks: cis_2.1.x.yml -- name: "SECTION | 2.2 | Service Clients" - ansible.builtin.import_tasks: - file: cis_2.2.x.yml +- name: "SECTION | 2.2 | Special Purpose Services" + ansible.builtin.import_tasks: cis_2.2.x.yml -- name: "SECTION | 2.3 | Time Synchronization" - ansible.builtin.import_tasks: - file: cis_2.3.x.yml +- name: "SECTION | 2.3 | Service Clients" + ansible.builtin.import_tasks: cis_2.3.x.yml -- name: "SECTION | 2.4 | Job Schedulers" - ansible.builtin.import_tasks: - file: cis_2.4.x.yml +- name: "SECTION | 2.4 | Nonessential services removed" + ansible.builtin.import_tasks: cis_2.4.yml diff --git a/tasks/section_3/cis_3.1.x.yml b/tasks/section_3/cis_3.1.x.yml index ff9ec46..7ffe31c 100644 --- a/tasks/section_3/cis_3.1.x.yml +++ b/tasks/section_3/cis_3.1.x.yml @@ -3,107 +3,81 @@ # The CIS Control wants IPv6 disabled if not in use. # We are using the rhel9cis_ipv6_required to specify if you have IPv6 in use - name: "3.1.1 | PATCH | Ensure IPv6 status is identified" - when: - - not rhel9cis_ipv6_required - - rhel9cis_rule_3_1_1 - tags: - - level1-server - - level1-workstation - - manual - - patch - - ipv6 - - networking - - rule_3.1.1 - - NIST800-53R5_CM-7 block: - - name: "3.1.1 | PATCH | Ensure IPv6 status is identified | Set vars for sysctl template" - when: "'sysctl' in rhel9cis_ipv6_disable_method" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - rhel9cis_flush_ipv6_route: true + - name: "3.1.1 | PATCH | Ensure IPv6 status is identified | refresh" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true + rhel9cis_flush_ipv6_route: true - - name: "3.1.1 | AUDIT | Ensure IPv6 status is identified | Message out implementation info" - when: "'sysctl' in rhel9cis_ipv6_disable_method" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-disable_ipv6.conf" - - - name: "3.1.1 | AUDIT | Ensure IPv6 status is identified | Find IPv6 status" - when: "'kernel' in rhel9cis_ipv6_disable_method" - ansible.builtin.command: grubby --info=ALL - changed_when: false - failed_when: false - register: discovered_rhel9cis_3_1_1_ipv6_status - - - name: "3.1.1 | PATCH | Ensure IPv6 status is identified | Disable IPV6 via Kernel" - when: - - "'kernel' in rhel9cis_ipv6_disable_method" - - "'ipv6.disable=1' not in discovered_rhel9cis_3_1_1_ipv6_status.stdout" - ansible.builtin.shell: grubby --update-kernel=ALL --args="ipv6.disable=1" + - name: "3.1.1 | PATCH | Ensure IPv6 status is identified | disable" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-disable_ipv6.conf" + when: + - not rhel9cis_ipv6_required + - rhel9cis_rule_3_1_1 + tags: + - level1-server + - level1-workstation + - manual + - patch + - ipv6 + - networking + - rule_3.1.1 - name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled" + block: + - name: "3.1.2 | AUDIT | Ensure wireless interfaces are disabled | Check if nmcli command is available" + ansible.builtin.shell: rpm -q NetworkManager + changed_when: false + failed_when: false + check_mode: false + register: rhel_09_nmcli_available + + - name: "3.1.2 | AUDIT | Ensure wireless interfaces are disabled | Check if wifi is enabled" + ansible.builtin.shell: nmcli radio wifi + register: rhel_09_wifi_enabled + changed_when: rhel_09_wifi_enabled.stdout != "disabled" + failed_when: false + when: rhel_09_nmcli_available.rc == 0 + + - name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Disable wifi if enabled" + ansible.builtin.shell: nmcli radio all off + changed_when: false + failed_when: false + when: rhel_09_wifi_enabled is changed when: - - rhel9cis_rule_3_1_2 - - discover_wireless_adapters.rc == 0 + - rhel9cis_rule_3_1_2 tags: - - level1-server - - patch - - rule_3.1.2 - - wireless - - NIST800-53R5_CM-7 - vars: - warn_control_id: '3.1.2' + - level1-server + - patch + - wireless + - rule_3.1.2 + +- name: "3.1.3 | PATCH | Ensure TIPC is disabled" block: - - name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Check for network-manager tool" - when: "rhel9cis_network_manager_package_name in ansible_facts.packages" - ansible.builtin.command: nmcli radio wifi - changed_when: false - failed_when: false - check_mode: false - register: discovered_wifi_status + - name: "3.1.3 | PATCH | Ensure TIPC is disabled" + ansible.builtin.template: + src: "etc/modprobe.d/modprobe.conf.j2" + dest: "/etc/modprobe.d/{{ item }}.conf" + mode: "0600" + owner: root + group: root + loop: + - tipc + # note the item used in the template - - name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Disable wireless if network-manager installed" - when: - - "rhel9cis_network_manager_package_name in ansible_facts.packages" - - "'enabled' in discovered_wifi_status.stdout" - ansible.builtin.command: nmcli radio all off - changed_when: discovered_nmcli_radio_off.rc == 0 - register: discovered_nmcli_radio_off - - - name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Warn about wireless if network-manager not installed" - when: "rhel9cis_network_manager_package_name not in ansible_facts.packages" - ansible.builtin.debug: - msg: "Warning!! You need to disable wireless interfaces manually since network-manager is not installed" - - - name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Set warning count" - when: "rhel9cis_network_manager_package_name not in ansible_facts.packages" - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "3.1.3 | PATCH | Ensure bluetooth services are not in use" - when: rhel9cis_rule_3_1_3 + - name: "3.1.3 | PATCH | Ensure TIPC is disabled | blacklist" + ansible.builtin.lineinfile: + path: /etc/modprobe.d/blacklist.conf + regexp: "^(#)?blacklist tipc(\\s|$)" + line: "blacklist tipc" + create: true + mode: 0600 + when: + - rhel9cis_rule_3_1_3 tags: - - level1-server - - level2-workstation - - patch - - bluetooth - - rule_3.1.3 - - NIST800-53R5_CM-7 - block: - - name: "3.1.3 | PATCH | Ensure bluetooth services are not in use | pkg" - when: - - not rhel9cis_bluetooth_service - - not rhel9cis_bluetooth_mask - ansible.builtin.package: - name: bluez - state: absent - - - name: "3.1.3 | PATCH | Ensure bluetooth services are not in use | mask" - when: - - not rhel9cis_bluetooth_service - - rhel9cis_bluetooth_mask - notify: Systemd daemon reload - ansible.builtin.systemd: - name: bluetooth.service - enabled: false - state: stopped - masked: true + - level2-server + - level2-workstation + - patch + - tipc + - rule_3.1.3 diff --git a/tasks/section_3/cis_3.2.x.yml b/tasks/section_3/cis_3.2.x.yml index 415d966..cc5567f 100644 --- a/tasks/section_3/cis_3.2.x.yml +++ b/tasks/section_3/cis_3.2.x.yml @@ -1,121 +1,52 @@ --- -- name: "3.2.1 | PATCH | Ensure dccp kernel module is not available" - when: rhel9cis_rule_3_2_1 - tags: - - level2-server - - level2-workstation - - patch - - rule_3.2.1 - - dccp - - NIST800-53R5_CM-7 - - NIST800-53R5_SI-4 +- name: "3.2.1 | PATCH | Ensure IP forwarding is disabled" block: - - name: "3.2.1 | PATCH | Ensure dccp kernel module is not available | modprobe" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/dccp.conf - regexp: '^(#)?install dccp(\\s|$)' - line: "{{ item }}" - create: true - mode: 'u-x,go-rwx' - loop: - - install dccp /bin/true - - blacklist dccp + - name: "3.2.1 | PATCH | Ensure IP forwarding is disabled | Disable IPv4 forwarding | Set Fact" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true + rhel9cis_flush_ipv4_route: true - - name: "3.2.1 | PATCH | Ensure dccp kernel module is not available | blacklist" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/blacklist.conf - regexp: "^(#)?blacklist dccp(\\s|$)" - line: "blacklist dccp" - create: true - mode: 'u-x,go-rwx' + - name: "3.2.1 | PATCH | Ensure IP forwarding is disabled | Disable IPv4 forwarding" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" -- name: "3.2.2 | PATCH | Ensure tipc kernel module is not available" - when: rhel9cis_rule_3_2_2 + - name: "3.2.1 | PATCH | Ensure IP forwarding is disabled | IPv6" + block: + - name: "3.2.1 | PATCH | Ensure IP forwarding is disabled | Disable IPv6 forwarding | Set Fact" + ansible.builtin.set_fact: + rhel9cis_flush_ipv6_route: true + + - name: "3.2.1 | PATCH | Ensure IP forwarding is disabled | Disable IPv6 forwarding" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl.conf" + + when: rhel9cis_ipv6_required + when: + - not rhel9cis_is_router + - rhel9cis_rule_3_2_1 tags: - - level2-server - - level2-workstation - - patch - - rule_3.2.2 - - tipc - - NIST800-53R5_CM-7 - - NIST800-53R5_SI-4 + - level1-server + - level1-workstation + - sysctl + - patch + - rule_3.2.1 + +- name: "3.2.2 | PATCH | Ensure packet redirect sending is disabled" block: - - name: "3.2.2 | PATCH | Ensure tipc kernel module is not available | modprobe" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/tipc.conf - regexp: '^(#)?install tipc(\\s|$)' - line: "{{ item }}" - create: true - mode: 'u-x,go-rwx' - loop: - - install tipc /bin/true - - blacklist tipc - - - name: "3.2.2 | PATCH | Ensure tipc kernel module is not available | blacklist" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/blacklist.conf - regexp: "^(#)?blacklist tipc(\\s|$)" - line: "blacklist tipc" - create: true - mode: 'u-x,go-rwx' - -- name: "3.2.3 | PATCH | Ensure rds kernel module is not available" - when: rhel9cis_rule_3_2_3 + - name: "3.2.2 | PATCH | Ensure packet redirect sending is disabled | Set Fact" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true + rhel9cis_flush_ipv4_route: true + - name: "3.2.2 | PATCH | Ensure packet redirect sending is disabled" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" + when: + - not rhel9cis_is_router + - rhel9cis_rule_3_2_2 tags: - - level2-server - - level2-workstation - - patch - - rule_3.2.3 - - rds - - NIST800-53R5_CM-7 - - NIST800-53R5_SI-4 - block: - - name: "3.2.3 | PATCH | Ensure rds kernel module is not available | modprobe" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/rds.conf - regexp: '^(#)?install rds(\\s|$)' - line: "{{ item }}" - create: true - mode: 'u-x,go-rwx' - loop: - - install rds /bin/true - - blacklist rds - - - name: "3.2.3 | PATCH | Ensure rds kernel module is not available | blacklist" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/blacklist.conf - regexp: "^(#)?blacklist rds(\\s|$)" - line: "blacklist rds" - create: true - mode: 'u-x,go-rwx' - -- name: "3.2.4 | PATCH | Ensure sctp kernel module is not available" - when: rhel9cis_rule_3_2_4 - tags: - - level2-server - - level2-workstation - - patch - - rule_3.2.4 - - sctp - - NIST800-53R5_CM-7 - - NIST800-53R5_SI-4 - block: - - name: "3.2.4 | PATCH | Ensure sctp kernel module is not available | modprobe" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/sctp.conf - regexp: '^(#)?install sctp(\\s|$)' - line: "{{ item }}" - create: true - mode: 'u-x,go-rwx' - loop: - - install sctp /bin/true - - blacklist sctp - - - name: "3.2.4 | PATCH | Ensure sctp kernel module is not available | blacklist" - ansible.builtin.lineinfile: - path: /etc/modprobe.d/blacklist.conf - regexp: "^(#)?blacklist sctp(\\s|$)" - line: "blacklist sctp" - create: true - mode: 'u-x,go-rwx' + - level1-server + - level1-workstation + - patch + - sysctl + - rule_3.2.2 diff --git a/tasks/section_3/cis_3.3.x.yml b/tasks/section_3/cis_3.3.x.yml index 0281f12..e8f3a5f 100644 --- a/tasks/section_3/cis_3.3.x.yml +++ b/tasks/section_3/cis_3.3.x.yml @@ -1,298 +1,194 @@ --- -- name: "3.3.1 | PATCH | Ensure IP forwarding is disabled" +- name: "3.3.1 | PATCH | Ensure source routed packets are not accepted" + block: + - name: "3.3.1 | PATCH | Ensure source routed packets are not accepted | IPv4 | Set Fact" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true + rhel9cis_flush_ipv4_route: true + - name: "3.3.1 | PATCH | Ensure source routed packets are not accepted | IPv4" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" + + - name: "3.3.1 | PATCH | Ensure source routed packets are not accepted | IPv6" + block: + - name: "3.3.1 | PATCH | Ensure source routed packets are not accepted | IPv6 | Set Fact" + ansible.builtin.set_fact: + rhel9cis_flush_ipv6_route: true + + - name: "3.3.1 | PATCH | Ensure source routed packets are not accepted | IPv6" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl.conf" + when: rhel9cis_ipv6_required when: - - not rhel9cis_is_router - - rhel9cis_rule_3_3_1 + - rhel9cis_rule_3_3_1 tags: - - level1-server - - level1-workstation - - sysctl - - patch - - rule_3.3.1 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 + - level1-server + - level1-workstation + - sysctl + - patch + - rule_3.3.1 + +- name: "3.3.2 | PATCH | Ensure ICMP redirects are not accepted" block: - - name: "3.3.1 | PATCH | Ensure IP forwarding is disabled | Disable IPv4 forwarding | Set Fact" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - rhel9cis_flush_ipv4_route: true + - name: "3.3.2 | PATCH | Ensure ICMP redirects are not accepted | IPv4 | Set Fact" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true + rhel9cis_flush_ipv4_route: true - - name: "3.3.1 | PATCH | Ensure IP forwarding is disabled | Disable IPv4 forwarding" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" + - name: "3.3.2 | PATCH | Ensure ICMP redirects are not accepted | IPv4" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" - - name: "3.3.1 | PATCH | Ensure IP forwarding is disabled | IPv6" - when: rhel9cis_ipv6_required - block: - - name: "3.3.1 | PATCH | Ensure IP forwarding is disabled | Disable IPv6 forwarding | Set Fact" - ansible.builtin.set_fact: - rhel9cis_flush_ipv6_route: true + - name: "3.3.2 | PATCH | Ensure ICMP redirects are not accepted | IPv6" + block: + - name: "3.3.2 | PATCH | Ensure ICMP redirects are not accepted | IPv6 | Set Fact" + ansible.builtin.set_fact: + rhel9cis_flush_ipv6_route: true - - name: "3.3.1 | PATCH | Ensure IP forwarding is disabled | Disable IPv6 forwarding" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl.conf" - -- name: "3.3.2 | PATCH | Ensure packet redirect sending is disabled" + - name: "3.3.2 | PATCH | Ensure ICMP redirects are not accepted | IPv6" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl.conf" + when: rhel9cis_ipv6_required when: - - not rhel9cis_is_router - - rhel9cis_rule_3_3_2 + - rhel9cis_rule_3_3_2 tags: - - level1-server - - level1-workstation - - patch - - sysctl - - rule_3.3.2 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - block: - - name: "3.3.2 | PATCH | Ensure packet redirect sending is disabled | Set Fact" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - rhel9cis_flush_ipv4_route: true - - name: "3.3.2 | PATCH | Ensure packet redirect sending is disabled" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" + - level1-server + - level1-workstation + - sysctl + - patch + - rule_3.3.2 -- name: "3.3.3 | PATCH | Ensure bogus ICMP responses are ignored" - when: rhel9cis_rule_3_3_3 +- name: "3.3.3 | PATCH | Ensure secure ICMP redirects are not accepted" + block: + - name: "3.3.3 | PATCH | Ensure secure ICMP redirects are not accepted | Set Fact" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true + rhel9cis_flush_ipv4_route: true + + - name: "3.3.3 | PATCH | Ensure secure ICMP redirects are not accepted" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" + when: + - rhel9cis_rule_3_3_3 tags: - - level1-server - - level1-workstation - - sysctl - - patch - - rule_3.3.3 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 + - level1-server + - level1-workstation + - sysctl + - patch + - rule_3.3.3 + +- name: "3.3.4 | PATCH | Ensure suspicious packets are logged" block: - - name: "3.3.3 | PATCH | Ensure bogus ICMP responses are ignored | Set Fact" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - rhel9cis_flush_ipv4_route: true + - name: "3.3.4 | PATCH | Ensure suspicious packets are logged | Set Fact" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true + rhel9cis_flush_ipv4_route: true - - name: "3.3.3 | PATCH | Ensure bogus ICMP responses are ignored" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" - -- name: "3.3.4 | PATCH | Ensure broadcast ICMP requests are ignored" - when: rhel9cis_rule_3_3_4 + - name: "3.3.4 | PATCH | Ensure suspicious packets are logged" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" + when: + - rhel9cis_rule_3_3_4 tags: - - level1-server - - level1-workstation - - sysctl - - patch - - rule_3.3.4 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 + - level1-server + - level1-workstation + - sysctl + - patch + - rule_3.3.4 + +- name: "3.3.5 | PATCH | Ensure broadcast ICMP requests are ignored" block: - - name: "3.3.4 | PATCH | Ensure broadcast ICMP requests are ignored | Set Fact" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - rhel9cis_flush_ipv4_route: true + - name: "3.3.5 | PATCH | Ensure broadcast ICMP requests are ignored | Set Fact" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true + rhel9cis_flush_ipv4_route: true - - name: 3.3.4 | PATCH | Ensure broadcast ICMP requests are ignored" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" - -- name: "3.3.5 | PATCH | Ensure ICMP redirects are not accepted" - when: rhel9cis_rule_3_3_5 + - name: 3.3.5 | PATCH | Ensure broadcast ICMP requests are ignored" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" + when: + - rhel9cis_rule_3_3_5 tags: - - level1-server - - level1-workstation - - sysctl - - patch - - rule_3.3.5 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 + - level1-server + - level1-workstation + - sysctl + - patch + - rule_3.3.5 + +- name: "3.3.6 | PATCH | Ensure bogus ICMP responses are ignored" block: - - name: "3.3.5 | PATCH | Ensure ICMP redirects are not accepted | Set Fact" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - rhel9cis_flush_ipv4_route: true + - name: "3.3.6 | PATCH | Ensure bogus ICMP responses are ignored | Set Fact" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true + rhel9cis_flush_ipv4_route: true - - name: "3.3.5 | PATCH | Ensure ICMP redirects are not accepted" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" - - - name: "3.3.5 | PATCH | Ensure ICMP redirects are not accepted | IPv6" - when: rhel9cis_ipv6_required - block: - - name: "3.3.5 | PATCH | Ensure ICMP redirects are not accepted | IPv6 | Set Fact" - ansible.builtin.set_fact: - rhel9cis_flush_ipv6_route: true - - - name: "3.3.5 | PATCH | Ensure ICMP redirects are not accepted | IPv6" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl.conf" - -- name: "3.3.6 | PATCH | Ensure secure ICMP redirects are not accepted" - when: rhel9cis_rule_3_3_6 + - name: "3.3.6 | PATCH | Ensure bogus ICMP responses are ignored" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" + when: + - rhel9cis_rule_3_3_6 tags: - - level1-server - - level1-workstation - - sysctl - - patch - - rule_3.3.6 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - block: - - name: "3.3.6 | PATCH | Ensure secure ICMP redirects are not accepted | IPv4 | Set Fact" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - rhel9cis_flush_ipv4_route: true - - - name: "3.3.6 | PATCH | Ensure secure ICMP redirects are not accepted | IPv4" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" - - - name: "3.3.6 | PATCH | Ensure secure ICMP redirects are not accepted | IPv6" - when: rhel9cis_ipv6_required - block: - - name: "3.3.6 | PATCH | Ensure secure ICMP redirects are not accepted | IPv6 | Set Fact" - ansible.builtin.set_fact: - rhel9cis_flush_ipv6_route: true - - - name: "3.3.6 | PATCH | Ensure secure ICMP redirects are not accepted | IPv6" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl.conf" + - level1-server + - level1-workstation + - sysctl + - patch + - rule_3.3.6 - name: "3.3.7 | PATCH | Ensure Reverse Path Filtering is enabled" - when: rhel9cis_rule_3_3_7 - tags: - - level1-server - - level1-workstation - - sysctl - - patch - - rule_3.3.7 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 block: - - name: "3.3.7 | PATCH | Ensure Reverse Path Filtering is enabled | Set Fact" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - rhel9cis_flush_ipv4_route: true + - name: "3.3.7 | PATCH | Ensure Reverse Path Filtering is enabled | Set Fact" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true + rhel9cis_flush_ipv4_route: true - - name: "3.3.7 | PATCH | Ensure Reverse Path Filtering is enabled" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" - -- name: "3.3.8 | PATCH | Ensure source routed packets are not accepted" - when: rhel9cis_rule_3_3_8 + - name: "3.3.7 | PATCH | Ensure Reverse Path Filtering is enabled" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" + when: + - rhel9cis_rule_3_3_7 tags: - - level1-server - - level1-workstation - - sysctl - - patch - - rule_3.3.8 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - block: - - name: "3.3.8 | PATCH | Ensure source routed packets are not accepted | IPv4 | Set Fact" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - rhel9cis_flush_ipv4_route: true - - name: "3.3.8 | PATCH | Ensure source routed packets are not accepted | IPv4" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" + - level1-server + - level1-workstation + - sysctl + - patch + - rule_3.3.7 - - name: "3.3.8 | PATCH | Ensure source routed packets are not accepted | IPv6" - when: rhel9cis_ipv6_required - block: - - name: "3.3.8 | PATCH | Ensure source routed packets are not accepted | IPv6 | Set Fact" - ansible.builtin.set_fact: +- name: "3.3.8 | PATCH | Ensure TCP SYN Cookies is enabled" + block: + - name: "3.3.8 | PATCH | Ensure TCP SYN Cookies is enabled | Set Fact" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true + rhel9cis_flush_ipv4_route: true + + - name: "3.3.8 | PATCH | Ensure TCP SYN Cookies is enabled" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" + when: + - rhel9cis_rule_3_3_8 + tags: + - level1-server + - level1-workstation + - sysctl + - patch + - rule_3.3.8 + +- name: "3.3.9 | PATCH | Ensure IPv6 router advertisements are not accepted" + block: + - name: "3.3.9 | PATCH | Ensure IPv6 router advertisements are not accepted | IPv6 | Set Fact" + ansible.builtin.set_fact: + rhel9cis_sysctl_update: true rhel9cis_flush_ipv6_route: true - - name: "3.3.8 | PATCH | Ensure source routed packets are not accepted | IPv6" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl.conf" - -- name: "3.3.9 | PATCH | Ensure suspicious packets are logged" - when: rhel9cis_rule_3_3_9 - tags: - - level1-server - - level1-workstation - - sysctl - - patch - - rule_3.3.9 - - NIST800-53R5_AU-3 - block: - - name: "3.3.9 | PATCH | Ensure suspicious packets are logged | Set Fact" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - rhel9cis_flush_ipv4_route: true - - - name: "3.3.9 | PATCH | Ensure suspicious packets are logged" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" - -- name: "3.3.10 | PATCH | Ensure TCP SYN Cookies is enabled" - when: rhel9cis_rule_3_3_10 - tags: - - level1-server - - level1-workstation - - sysctl - - patch - - rule_3.3.10 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - block: - - name: "3.3.10 | PATCH | Ensure TCP SYN Cookies is enabled | Set Fact" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - rhel9cis_flush_ipv4_route: true - - - name: "3.3.10 | PATCH | Ensure TCP SYN Cookies is enabled" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf" - -- name: "3.3.11 | PATCH | Ensure IPv6 router advertisements are not accepted" + - name: "3.3.9 | PATCH | Ensure IPv6 router advertisements are not accepted | IPv6" + ansible.builtin.debug: + msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl" when: - - rhel9cis_ipv6_required - - rhel9cis_rule_3_3_11 + - rhel9cis_ipv6_required + - rhel9cis_rule_3_3_9 tags: - - level2-server - - level2-workstation - - sysctl - - patch - - rule_3.3.11 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - block: - - name: "3.3.11 | PATCH | Ensure IPv6 router advertisements are not accepted | IPv6 | Set Fact" - ansible.builtin.set_fact: - rhel9cis_sysctl_update: true - rhel9cis_flush_ipv6_route: true - - - name: "3.3.11 | PATCH | Ensure IPv6 router advertisements are not accepted | IPv6" - ansible.builtin.debug: - msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv6_sysctl" + - level2-server + - level2-workstation + - sysctl + - patch + - rule_3.3.9 diff --git a/tasks/section_3/cis_3.4.1.x.yml b/tasks/section_3/cis_3.4.1.x.yml new file mode 100644 index 0000000..8a7e721 --- /dev/null +++ b/tasks/section_3/cis_3.4.1.x.yml @@ -0,0 +1,59 @@ +--- + +- name: "3.4.1.1 | PATCH | Ensure nftables is installed" + ansible.builtin.package: + name: + - nftables + state: present + when: + - rhel9cis_rule_3_4_1_1 + - rhel9cis_firewall == 'nftables' + tags: + - level1-server + - level1-workstation + - patch + - nftables + - rule_3.4.1.1 + +- name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use" + block: + - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | nftables" + ansible.builtin.systemd: + name: "{{ item }}" + masked: true + loop: + - firewalld + when: + - item in ansible_facts.packages + - rhel9cis_firewall == 'nftables' + + - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | firewalld" + ansible.builtin.systemd: + name: "{{ item }}" + masked: true + loop: + - nftables + when: + - item in ansible_facts.packages + - rhel9cis_firewall == 'firewalld' + + - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | package installed" + ansible.builtin.package: + name: "{{ rhel9cis_firewall }}" + state: installed + + - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | {{ rhel9cis_firewall }} started and enabled" + ansible.builtin.systemd: + name: "{{ rhel9cis_firewall }}" + enabled: true + state: started + + when: + - rhel9cis_rule_3_4_1_2 + tags: + - level1-server + - level1-workstation + - patch + - firewalld + - nftables + - rule_3.4.1.2 diff --git a/tasks/section_3/cis_3.4.2.x.yml b/tasks/section_3/cis_3.4.2.x.yml new file mode 100644 index 0000000..865fe59 --- /dev/null +++ b/tasks/section_3/cis_3.4.2.x.yml @@ -0,0 +1,299 @@ +--- + +- name: "3.4.2.1 | PATCH | Ensure firewalld default zone is set" + block: + - name: "3.4.2.1 | AUDIT | Ensure firewalld default zone is set" + ansible.builtin.shell: "firewall-cmd --get-default-zone | grep {{ rhel9cis_default_zone }}" + changed_when: false + failed_when: ( firewalld_zone_set.rc not in [ 0, 1 ] ) + register: firewalld_zone_set + + - name: "3.4.2.1 | AUDIT | Ensure firewalld default zone is set" + ansible.builtin.command: firewall-cmd --set-default-zone="{{ rhel9cis_default_zone }}" + when: firewalld_zone_set.rc != 0 + when: + - rhel9cis_firewall == "firewalld" + - rhel9cis_rule_3_4_2_1 + tags: + - level1-server + - level1-workstation + - patch + - firewalld + - rule_3.4.2.1 + +- name: "3.4.2.2 | AUDIT | Ensure at least one nftables table exists" + block: + - name: "3.4.2.2 | AUDIT | Ensure a table exists | Check for tables" + ansible.builtin.command: nft list tables + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_2_nft_tables + + - name: "3.4.2.2 | AUDIT | Ensure an nftables table exists | Show existing tables" + ansible.builtin.debug: + msg: + - "Below are the current nft tables, please review" + - "{{ rhel9cis_3_4_2_2_nft_tables.stdout_lines }}" + when: rhel9cis_3_4_2_2_nft_tables.stdout | length > 0 + + - name: "3.4.2.2 | AUDIT | Ensure an nftables table exists | Alert on no tables" + ansible.builtin.debug: + msg: + - "Warning!! You currently have no nft tables, please review your setup" + - 'Use the command "nft create table inet " to create a new table' + when: + - rhel9cis_3_4_2_2_nft_tables.stdout | length == 0 + - not rhel9cis_nft_tables_autonewtable + + - name: "3.4.2.2 | AUDIT | Ensure an nftables table exists | Alert on no tables | warning count" + ansible.builtin.import_tasks: warning_facts.yml + when: + - rhel9cis_3_4_2_2_nft_tables.stdout | length == 0 + - not rhel9cis_nft_tables_autonewtable + + - name: "3.4.2.2 | PATCH | Ensure a table exists | Create table if needed" + ansible.builtin.command: nft create table inet "{{ rhel9cis_nft_tables_tablename }}" + failed_when: false + when: rhel9cis_nft_tables_autonewtable + vars: + warn_control_id: '3.4.2.2' + when: + - rhel9cis_firewall == "nftables" + - rhel9cis_rule_3_4_2_2 + tags: + - level1-server + - level1-workstation + - patch + - nftables + - rule_3.4.2.2 + +- name: "3.4.2.3 | PATCH | Ensure nftables base chains exist" + block: + - name: "3.4.2.3 | AUDIT | Ensure nftables base chains exist | Get current chains for INPUT" + ansible.builtin.shell: nft list ruleset | grep 'hook input' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_3_input_chains + + - name: "3.4.2.3 | AUDIT | Ensure nftables base chains exist | Get current chains for FORWARD" + ansible.builtin.shell: nft list ruleset | grep 'hook forward' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_3_forward_chains + + - name: "3.4.2.3 | AUDIT | Ensure nftables base chains exist | Get current chains for OUTPUT" + ansible.builtin.shell: nft list ruleset | grep 'hook output' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_3_output_chains + + - name: "3.4.2.3 | AUDIT | Ensure nftables base chains exist | Display chains for review" + ansible.builtin.debug: + msg: + - "Below are the current INPUT chains" + - "{{ rhel9cis_3_4_2_3_input_chains.stdout_lines }}" + - "Below are the current FORWARD chains" + - "{{ rhel9cis_3_4_2_3_forward_chains.stdout_lines }}" + - "Below are teh current OUTPUT chains" + - "{{ rhel9cis_3_4_2_3_output_chains.stdout_lines }}" + when: not rhel9cis_nft_tables_autochaincreate + + - name: "3.4.2.3 | PATCH | Ensure nftables base chains exist | Create chains if needed" + ansible.builtin.shell: "{{ item }}" + failed_when: false + loop: + - nft create chain inet "{{ rhel9cis_nft_tables_tablename }}" input { type filter hook input priority 0 \; } + - nft create chain inet "{{ rhel9cis_nft_tables_tablename }}" forward { type filter hook forward priority 0 \; } + - nft create chain inet "{{ rhel9cis_nft_tables_tablename }}" output { type filter hook output priority 0 \; } + when: rhel9cis_nft_tables_autochaincreate + when: + - rhel9cis_firewall == "nftables" + - rhel9cis_rule_3_4_2_3 + tags: + - level1-server + - level1-workstation + - patch + - nftables + - rule_3.4.2.3 + +- name: "3.4.2.4 | PATCH | Ensure host based firewall loopback traffic is configured" + block: + - name: "3.4.2.4 | AUDIT | Ensure host based firewall loopback traffic is configured | Gather iif lo accept existence | nftables" + ansible.builtin.shell: nft list ruleset | awk '/hook input/,/}/' | grep 'iif "lo" accept' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_4_iiflo + + - name: "3.4.2.4 | AUDIT | Ensure host based firewall loopback traffic is configured | Gather ip saddr existence | nftables" + ansible.builtin.shell: nft list ruleset | awk '/hook input/,/}/' | grep 'ip saddr' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_4_ipsaddr + + - name: "3.4.2.4 | AUDIT | Ensure host based firewall loopback traffic is configured | Gather ip6 saddr existence | nftables" + ansible.builtin.shell: nft list ruleset | awk '/hook input/,/}/' | grep 'ip6 saddr' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_4_ip6saddr + + - name: "3.4.2.4 | PATCH | Ensure host based firewall loopback traffic is configured | Set iif lo accept rule | nftables" + ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input iif lo accept + when: '"iif \"lo\" accept" not in rhel9cis_3_4_2_4_iiflo.stdout' + + - name: "3.4.2.4 | PATCH | Ensure host based firewall loopback traffic is configured | Set ip sddr rule | nftables" + ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip saddr 127.0.0.0/8 counter drop + when: '"ip saddr 127.0.0.0/8 counter packets 0 bytes 0 drop" not in rhel9cis_3_4_2_4_ipsaddr.stdout' + + - name: "3.4.2.4 | PATCH | Ensure host based firewall loopback traffic is configured | Set ip6 saddr rule | nftables" + ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip6 saddr ::1 counter drop + when: '"ip6 saddr ::1 counter packets 0 bytes 0 drop" not in rhel9cis_3_4_2_4_ip6saddr.stdout' + when: + - rhel9cis_firewall == "nftables" + - rhel9cis_rule_3_4_2_4 + tags: + - level1-server + - level1-workstation + - patch + - nftables + - rule_3.4.2.4 + +- name: "3.4.2.4 | PATCH | Ensure host based firewall loopback traffic is configured | firewalld" + ansible.posix.firewalld: + rich_rule: "{{ item }}" + zone: "{{ rhel9cis_default_zone }}" + permanent: true + immediate: true + state: enabled + loop: + - rule family="ipv4" source address="127.0.0.1" destination not address="127.0.0.1" drop + - rule family="ipv6" source address="::1" destination not address="::1" drop + when: + - rhel9cis_firewall == "firewalld" + - rhel9cis_rule_3_4_2_4 + tags: + - level1-server + - level1-workstation + - patch + - nftables + - rule_3.4.2.4 + +- name: "3.4.2.5 | AUDIT | Ensure firewalld drops unnecessary services and ports" + block: + - name: "3.4.2.5 | AUDIT | Ensure firewalld drops unnecessary services and ports | Get list of services and ports" + ansible.builtin.shell: "firewall-cmd --get-active-zones | awk '!/:/ {print $1}' | while read ZN; do firewall-cmd --list-all --zone=$ZN; done" + changed_when: false + failed_when: false + check_mode: false + register: rhel9cis_3_4_2_5_servicesport + + - name: "3.4.2.5 | AUDIT | Ensure firewalld drops unnecessary services and ports | Show services and ports" + ansible.builtin.debug: + msg: + - "The items below are the services and ports that are accepted, please correct as needed" + - "{{ rhel9cis_3_4_2_5_servicesport.stdout_lines }}" + when: + - rhel9cis_rule_3_4_2_5 + tags: + - level1-server + - level1-workstation + - manual + - audit + - rule_3.4.2.5 + +- name: "3.4.2.6 | PATCH | Ensure nftables established connections are configured" + block: + - name: "3.4.2.6 | AUDIT | EEnsure nftables established connections are configured | Gather incoming connection rules" + ansible.builtin.shell: nft list ruleset | awk '/hook input/,/}/' | grep -E 'ip protocol (tcp|udp|icmp) ct state' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_6_inconnectionrule + + - name: "3.4.2.6| AUDIT | Ensure nftables established connections are configured | Gather outbound connection rules" + ansible.builtin.shell: nft list ruleset | awk '/hook output/,/}/' | grep -E 'ip protocol (tcp|udp|icmp) ct state' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_6_outconnectionrule + + - name: "3.4.2.6| PATCH | Ensure nftables established connections are configured | Add input tcp established accept policy" + ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip protocol tcp ct state established accept + when: '"ip protocol tcp ct state established accept" not in rhel9cis_3_4_2_6_inconnectionrule.stdout' + + - name: "3.4.2.6 | PATCH | Ensure nftables established connections are configured | Add input udp established accept policy" + ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip protocol udp ct state established accept + when: '"ip protocol udp ct state established accept" not in rhel9cis_3_4_2_6_inconnectionrule.stdout' + + - name: "3.4.2.6 | PATCH | Ensure nftables established connections are configured | Add input icmp established accept policy" + ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip protocol icmp ct state established accept + when: '"ip protocol icmp ct state established accept" not in rhel9cis_3_4_2_6_inconnectionrule.stdout' + + - name: "3.4.2.6 | PATCH | Ensure nftables established connections are configured | Add output tcp new, related, established accept policy" + ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" output ip protocol tcp ct state new,related,established accept + when: '"ip protocol tcp ct state established,related,new accept" not in rhel9cis_3_4_2_6_outconnectionrule.stdout' + + - name: "3.4.2.6 | PATCH | Ensure nftables established connections are configured | Add output udp new, related, established accept policy" + ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" output ip protocol udp ct state new,related,established accept + when: '"ip protocol udp ct state established,related,new accept" not in rhel9cis_3_4_2_6_outconnectionrule.stdout' + + - name: "3.4.2.6 | PATCH | Ensure nftables established connections are configured | Add output icmp new, related, established accept policy" + ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" output ip protocol icmp ct state new,related,established accept + when: '"ip protocol icmp ct state established,related,new accept" not in rhel9cis_3_4_2_6_outconnectionrule.stdout' + when: + - rhel9cis_firewall == "nftables" + - rhel9cis_rule_3_4_2_6 + tags: + - level1-server + - level1-workstation + - patch + - nftables + - rule_3.4.2.6 + +- name: "3.4.2.7 | PATCH | Ensure nftables default deny firewall policy" + block: + - name: "3.4.2.7 | AUDIT | Ensure nftables default deny firewall policy | Check for hook input deny policy" + ansible.builtin.shell: nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'hook input' + failed_when: false + changed_when: false + register: rhel9cis_3_4_2_7_inputpolicy + + - name: "3.4.2.7 | AUDIT | Ensure nftables default deny firewall policy | Check for hook forward deny policy" + ansible.builtin.shell: nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'hook forward' + failed_when: false + changed_when: false + register: rhel9cis_3_4_2_7_forwardpolicy + + - name: "3.4.2.7 | AUDIT | Ensure nftables default deny firewall policy | Check for hook output deny policy" + ansible.builtin.shell: nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'hook output' + failed_when: false + changed_when: false + register: rhel9cis_3_4_2_7_outputpolicy + + - name: "3.4.2.7 | AUDIT | Ensure nftables default deny firewall policy | Check for SSH allow" + ansible.builtin.shell: nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'ssh' + failed_when: false + changed_when: false + register: rhel9cis_3_4_2_7_sshallowcheck + + - name: "3.4.2.7 | PATCH | Ensure nftables default deny firewall policy | Enable SSH traffic" + ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input tcp dport ssh accept + when: '"tcp dport ssh accept" not in rhel9cis_3_4_2_7_sshallowcheck.stdout' + + - name: "3.4.2.7 | PATCH | Ensure nftables default deny firewall policy | Set hook input deny policy" + ansible.builtin.command: nft chain inet "{{ rhel9cis_nft_tables_tablename }}" input { policy drop \; } + when: '"type filter hook input priority 0; policy drop;" not in rhel9cis_3_4_2_7_inputpolicy.stdout' + + - name: "3.4.2.7 | PATCH | Ensure nftables default deny firewall policy | Create hook forward deny policy" + ansible.builtin.command: nft chain inet "{{ rhel9cis_nft_tables_tablename }}" forward { policy drop \; } + when: '"type filter hook forward priority 0; policy drop;" not in rhel9cis_3_4_2_7_forwardpolicy.stdout' + + - name: "3.4.2.7 | PATCH | Ensure nftables default deny firewall policy | Create hook output deny policy" + ansible.builtin.command: nft chain inet "{{ rhel9cis_nft_tables_tablename }}" output { policy drop \; } + when: '"type filter hook output priority 0; policy drop;" not in rhel9cis_3_4_2_7_outputpolicy.stdout' + when: + - rhel9cis_firewall == "nftables" + - rhel9cis_rule_3_4_2_7 + tags: + - level1-server + - level1-workstation + - patch + - nftables + - rule_3.4.2.7 diff --git a/tasks/section_3/main.yml b/tasks/section_3/main.yml index bd4442d..535aba9 100644 --- a/tasks/section_3/main.yml +++ b/tasks/section_3/main.yml @@ -1,13 +1,16 @@ --- -- name: "SECTION | 3.1.x | Configure Network Devices" - ansible.builtin.import_tasks: - file: cis_3.1.x.yml +- name: "SECTION | 3.1.x | Disable unused network protocols and devices" + ansible.builtin.import_tasks: cis_3.1.x.yml -- name: "SECTION | 3.2.x | Configure Network Kernel Modules" - ansible.builtin.import_tasks: - file: cis_3.2.x.yml +- name: "SECTION | 3.2.x | Network Parameters (Host Only)" + ansible.builtin.import_tasks: cis_3.2.x.yml -- name: "SECTION | 3.3.x | Configure Network Kernel Parameters" - ansible.builtin.import_tasks: - file: cis_3.3.x.yml +- name: "SECTION | 3.3.x | Network Parameters (host and Router)" + ansible.builtin.import_tasks: cis_3.3.x.yml + +- name: "SECTION | 3.4.1.x | Firewall configuration" + ansible.builtin.import_tasks: cis_3.4.1.x.yml + +- name: "SECTION | 3.4.2.x | Configure firewall" + ansible.builtin.import_tasks: cis_3.4.2.x.yml diff --git a/tasks/section_4/cis_4.1.1.x.yml b/tasks/section_4/cis_4.1.1.x.yml new file mode 100644 index 0000000..a8be25f --- /dev/null +++ b/tasks/section_4/cis_4.1.1.x.yml @@ -0,0 +1,105 @@ +--- + +- name: "4.1.1.1 | PATCH | Ensure auditd is installed" + block: + - name: "4.1.1.1 | PATCH | Ensure auditd is installed | Install auditd packages" + ansible.builtin.package: + name: audit + state: present + when: '"auditd" not in ansible_facts.packages' + + - name: "4.1.1.1 | PATCH | Ensure auditd is installed | Install auditd-lib packages" + ansible.builtin.package: + name: audit-libs + state: present + when: '"auditd-lib" not in ansible_facts.packages' + when: + - rhel9cis_rule_4_1_1_1 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.1.1 + +- name: "4.1.1.2 | PATCH | Ensure auditing for processes that start prior to auditd is enabled" + block: + - name: "4.1.1.2 | AUDIT | Ensure auditing for processes that start prior to auditd is enabled | Get GRUB_CMDLINE_LINUX" + ansible.builtin.shell: grep 'GRUB_CMDLINE_LINUX=' /etc/default/grub | sed 's/.$//' + changed_when: false + failed_when: false + check_mode: false + register: rhel9cis_4_1_1_2_grub_cmdline_linux + + - name: "4.1.1.2 | PATCH | Ensure auditing for processes that start prior to auditd is enabled | Replace existing setting" + ansible.builtin.replace: + path: /etc/default/grub + regexp: 'audit=.' + replace: 'audit=1' + notify: Grub2cfg + when: "'audit=' in rhel9cis_4_1_1_2_grub_cmdline_linux.stdout" + + - name: "4.1.1.2 | PATCH | Ensure auditing for processes that start prior to auditd is enabled | Add audit setting if missing" + ansible.builtin.lineinfile: + path: /etc/default/grub + regexp: '^GRUB_CMDLINE_LINUX=' + line: '{{ rhel9cis_4_1_1_2_grub_cmdline_linux.stdout }} audit=1"' + notify: Grub2cfg + when: "'audit=' not in rhel9cis_4_1_1_2_grub_cmdline_linux.stdout" + when: + - rhel9cis_rule_4_1_1_2 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - grub + - rule_4.1.1.2 + +- name: "4.1.1.3 | PATCH | Ensure audit_backlog_limit is sufficient" + block: + - name: "4.1.1.3 | AUDIT | Ensure audit_backlog_limit is sufficient | Get GRUB_CMDLINE_LINUX" + ansible.builtin.shell: grep 'GRUB_CMDLINE_LINUX=' /etc/default/grub | sed 's/.$//' + changed_when: false + failed_when: false + check_mode: false + register: rhel9cis_4_1_1_3_grub_cmdline_linux + + - name: "4.1.1.3 | PATCH | Ensure audit_backlog_limit is sufficient | Replace existing setting" + ansible.builtin.replace: + path: /etc/default/grub + regexp: 'audit_backlog_limit=\d+' + replace: 'audit_backlog_limit={{ rhel9cis_audit_back_log_limit }}' + notify: Grub2cfg + when: "'audit_backlog_limit=' in rhel9cis_4_1_1_3_grub_cmdline_linux.stdout" + + - name: "4.1.1.3 | PATCH | Ensure audit_backlog_limit is sufficient | Add audit_backlog_limit setting if missing" + ansible.builtin.lineinfile: + path: /etc/default/grub + regexp: '^GRUB_CMDLINE_LINUX=' + line: '{{ rhel9cis_4_1_1_3_grub_cmdline_linux.stdout }} audit_backlog_limit={{ rhel9cis_audit_back_log_limit }}"' + notify: Grub2cfg + when: "'audit_backlog_limit=' not in rhel9cis_4_1_1_3_grub_cmdline_linux.stdout" + when: + - rhel9cis_rule_4_1_1_3 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - grub + - rule_4.1.1.3 + +- name: "4.1.1.4 | PATCH | Ensure auditd service is enabled" + ansible.builtin.systemd: + name: auditd + state: started + enabled: true + when: + - rhel9cis_rule_4_1_1_4 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.1.4 diff --git a/tasks/section_4/cis_4.1.2.x.yml b/tasks/section_4/cis_4.1.2.x.yml new file mode 100644 index 0000000..b830b1f --- /dev/null +++ b/tasks/section_4/cis_4.1.2.x.yml @@ -0,0 +1,65 @@ +--- + +- name: "4.1.2.1 | PATCH | Ensure audit log storage size is configured" + ansible.builtin.lineinfile: + path: /etc/audit/auditd.conf + regexp: "^max_log_file( |=)" + line: "max_log_file = {{ rhel9cis_max_log_file_size }}" + notify: Restart auditd + when: + - rhel9cis_rule_4_1_2_1 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.2.1 + +- name: "4.1.2.2 | PATCH | Ensure audit logs are not automatically deleted" + ansible.builtin.lineinfile: + path: /etc/audit/auditd.conf + regexp: "^max_log_file_action" + line: "max_log_file_action = {{ rhel9cis_auditd['max_log_file_action'] }}" + notify: Restart auditd + when: + - rhel9cis_rule_4_1_2_2 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.2.2 + +- name: "4.1.2.3 | PATCH | Ensure system is disabled when audit logs are full" + ansible.builtin.lineinfile: + path: /etc/audit/auditd.conf + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + notify: Restart auditd + loop: + - { regexp: '^admin_space_left_action', line: 'admin_space_left_action = {{ rhel9cis_auditd.admin_space_left_action }}' } + - { regexp: '^action_mail_acct', line: 'action_mail_acct = {{ rhel9cis_auditd.action_mail_acct }}' } + - { regexp: '^space_left_action', line: 'space_left_action = {{ rhel9cis_auditd.space_left_action }}' } + when: + - rhel9cis_rule_4_1_2_3 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.2.3 + +- name: PATCH | Configure other keys for auditd.conf + ansible.builtin.lineinfile: + path: /etc/audit/auditd.conf + regexp: "^{{ item }}( |=)" + line: "{{ item }} = {{ rhel9cis_auditd_extra_conf[item] }}" + loop: "{{ rhel9cis_auditd_extra_conf.keys() }}" + notify: Restart auditd + when: + - rhel9cis_auditd_extra_conf.keys() | length > 0 + tags: + - level2-server + - level2-workstation + - patch + - auditd diff --git a/tasks/section_4/cis_4.1.3.x.yml b/tasks/section_4/cis_4.1.3.x.yml new file mode 100644 index 0000000..922ea61 --- /dev/null +++ b/tasks/section_4/cis_4.1.3.x.yml @@ -0,0 +1,292 @@ +--- + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.1 | PATCH | Ensure changes to system administration scope (sudoers) is collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_1 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.1 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.2 | PATCH | Ensure actions as another user are always logged" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_2 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.2 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.3 | PATCH | Ensure events that modify the sudo log file are collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_3 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.3 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.4 | PATCH | Ensure events that modify date and time information are collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_4 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.4 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.5 | PATCH | Ensure events that modify the system's network environment are collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_5 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.5 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.6 | PATCH | Ensure use of privileged commands is collected" + block: + - name: "4.1.3.6 | PATCH | Ensure use of privileged commands is collected" + ansible.builtin.shell: for i in $(df | grep '^/dev' | awk '{ print $NF }'); do find $i -xdev -type f -perm -4000 -o -type f -perm -2000 2>/dev/null; done + changed_when: false + failed_when: false + check_mode: false + register: priv_procs + + - name: "4.1.3.6 | PATCH | Ensure use of privileged commands is collected" + ansible.builtin.set_fact: + update_audit_template: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_6 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.6 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.7 | PATCH | Ensure unsuccessful unauthorized file access attempts are collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_7 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3_7 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.8 | PATCH | Ensure events that modify user/group information are collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_8 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.8 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.9 | PATCH | Ensure discretionary access control permission modification events are collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_9 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.9 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.10 | PATCH | Ensure successful file system mounts are collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_10 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.10 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.11 | PATCH | Ensure session initiation information is collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_11 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.11 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.12 | PATCH | Ensure login and logout events are collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_12 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.12 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.13 | PATCH | Ensure file deletion events by users are collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_13 + tags: + - level2-server + - level2-workstation + - auditd + - patch + - rule_4.1.3.13 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.14 | PATCH | Ensure events that modify the system's Mandatory Access Controls are collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_14 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.14 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.15 | PATCH | Ensure successful and unsuccessful attempts to use the chcon command are recorded" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_15 + tags: + - level2-server + - level2- workstation + - patch + - auditd + - rule_4.1.3.15 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.16 | PATCH | Ensure successful and unsuccessful attempts to use the setfacl command are recorded" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_16 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.16 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.17 | PATCH | Ensure successful and unsuccessful attempts to use the chacl command are recorded" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_17 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.17 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.18 | PATCH | Ensure successful and unsuccessful attempts to use the usermod command are recorded" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_18 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.18 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.19 | PATCH | Ensure kernel module loading and unloading is collected" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_19 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.3.19 + +# All changes selected are managed by the POST audit and handlers to update +- name: "4.1.3.20 | PATCH | Ensure the audit configuration is immutable" + ansible.builtin.set_fact: + update_audit_template: true + when: + - rhel9cis_rule_4_1_3_20 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.20 + +- name: "4.1.3.21 | AUDIT | Ensure the running and on disk configuration is the same" + ansible.builtin.debug: + msg: + - "Please run augenrules --load if you suspect there is a configuration that is not active" + when: + - rhel9cis_rule_4_1_3_21 + tags: + - level2-server + - level2-workstation + - manual + - patch + - auditd + - rule_4.1.3.21 + +- name: Auditd | 4.1.3 | Auditd controls updated + ansible.builtin.debug: + msg: "Auditd Controls handled in POST using template - updating /etc/auditd/rules.d/99_auditd.rules" + changed_when: false + when: + - update_audit_template diff --git a/tasks/section_4/cis_4.1.4.x.yml b/tasks/section_4/cis_4.1.4.x.yml new file mode 100644 index 0000000..ec3eebd --- /dev/null +++ b/tasks/section_4/cis_4.1.4.x.yml @@ -0,0 +1,184 @@ +--- + +- name: | + "4.1.4.1 | PATCH | Ensure audit log files are mode 0640 or less permissive" + "4.1.4.2 | PATCH | Ensure only authorized users own audit log files" + "4.1.4.3 | PATCH | Ensure only authorized groups are assigned ownership of audit log files" + + block: + - name: "4.1.4.1 | AUDIT | Ensure audit log files are mode 0640 or less permissive | discover file" + ansible.builtin.shell: grep ^log_file /etc/audit/auditd.conf | awk '{ print $NF }' + changed_when: false + register: audit_discovered_logfile + + - name: "4.1.4.1 | AUDIT | Ensure audit log files are mode 0640 or less permissive | stat file" + ansible.builtin.stat: + path: "{{ audit_discovered_logfile.stdout }}" + changed_when: false + register: auditd_logfile + + - name: | + "4.1.4.1 | PATCH | Ensure audit log files are mode 0640 or less permissive" + "4.1.4.2 | PATCH | Ensure only authorized users own audit log files" + "4.1.4.3 | PATCH | Ensure only authorized groups are assigned ownership of audit log files" + ansible.builtin.file: + path: "{{ audit_discovered_logfile.stdout }}" + mode: "{% if auditd_logfile.stat.mode != '0600' %}0640{% endif %}" + owner: root + group: root + when: + - rhel9cis_rule_4_1_4_1 or + rhel9cis_rule_4_1_4_2 or + rhel9cis_rule_4_1_4_3 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.4.1 + - rule_4.1.4.2 + - rule_4.1.4.3 + +- name: "4.1.4.4 | PATCH | Ensure the audit log directory is 0750 or more restrictive" + block: + - name: "4.1.4.4 | AUDIT | Ensure the audit log directory is 0750 or more restrictive | get current permissions" + ansible.builtin.stat: + path: "{{ audit_discovered_logfile.stdout | dirname }}" + register: auditlog_dir + + - name: "4.1.4.4 | PATCH | Ensure the audit log directory is 0750 or more restrictive | set" + ansible.builtin.file: + path: "{{ audit_discovered_logfile.stdout | dirname }}" + state: directory + mode: 0750 + when: not auditlog_dir.stat.mode is match('07(0|5)0') + when: + - rhel9cis_rule_4_1_4_4 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.4.4 + +- name: "4.1.4.5 | PATCH | Ensure audit configuration files are 640 or more restrictive" + ansible.builtin.file: + path: "{{ item.path }}" + mode: 0640 + loop: "{{ auditd_conf_files.files }}" + loop_control: + label: "{{ item.path }}" + when: + - item.mode != '06(0|4)0' + - rhel9cis_rule_4_1_4_5 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.4.5 + +- name: "4.1.4.6 | PATCH | Ensure audit configuration files are owned by root" + ansible.builtin.file: + path: "{{ item.path }}" + owner: root + loop: "{{ auditd_conf_files.files }}" + loop_control: + label: "{{ item.path }}" + when: + - rhel9cis_rule_4_1_4_6 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.4.6 + +- name: "4.1.4.7 | PATCH | Ensure audit configuration files belong to group root" + ansible.builtin.file: + path: "{{ item.path }}" + group: root + loop: "{{ auditd_conf_files.files }}" + loop_control: + label: "{{ item.path }}" + when: + - rhel9cis_rule_4_1_4_7 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.4.7 + +- name: "4.1.4.8 | PATCH | Ensure audit tools are 755 or more restrictive" + block: + - name: "4.1.4.8 | AUDIT | Get audit binary file stat | get current mode" + ansible.builtin.stat: + path: "{{ item }}" + register: "audit_bins" + loop: + - /sbin/auditctl + - /sbin/aureport + - /sbin/ausearch + - /sbin/autrace + - /sbin/auditd + - /sbin/augenrules + + - name: "4.1.4.8 | PATCH | Ensure audit tools are 755 or more restrictive | set if required" + ansible.builtin.file: + path: "{{ item.item }}" + mode: 0750 + + loop: "{{ audit_bins.results }}" + loop_control: + label: "{{ item.item }}" + when: not item.stat.mode is match('07(0|5)0') + when: + - rhel9cis_rule_4_1_4_8 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.4.8 + +- name: "4.1.4.9 | PATCH | Ensure audit tools are owned by root" + ansible.builtin.file: + path: "{{ item }}" + owner: root + group: root + loop: + - /sbin/auditctl + - /sbin/aureport + - /sbin/ausearch + - /sbin/autrace + - /sbin/auditd + - /sbin/augenrules + when: + - rhel9cis_rule_4_1_4_9 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.4.9 + +- name: "4.1.4.10 | PATCH | Ensure audit tools belong to group root" + ansible.builtin.file: + path: "{{ item }}" + group: root + loop: + - /sbin/auditctl + - /sbin/aureport + - /sbin/ausearch + - /sbin/autrace + - /sbin/auditd + - /sbin/augenrules + when: + - rhel9cis_rule_4_1_4_10 + tags: + - level2-server + - level2-workstation + - patch + - auditd + - rule_4.1.4.10 diff --git a/tasks/section_4/cis_4.1.x.yml b/tasks/section_4/cis_4.1.x.yml deleted file mode 100644 index ab61c81..0000000 --- a/tasks/section_4/cis_4.1.x.yml +++ /dev/null @@ -1,58 +0,0 @@ ---- - -- name: "4.1.1 | PATCH | Ensure nftables is installed" - when: - - rhel9cis_rule_4_1_1 - - rhel9cis_firewall == 'nftables' - tags: - - level1-server - - level1-workstation - - patch - - nftables - - rule_4.1.1 - - NIST800-53R5_CA-9 - ansible.builtin.package: - name: - - nftables - state: present - -- name: "4.1.2 | PATCH | Ensure a single firewall configuration utility is in use" - when: rhel9cis_rule_4_1_2 - tags: - - level1-server - - level1-workstation - - patch - - firewalld - - nftables - - rule_4.1.2 - block: - - name: "4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | nftables" - when: - - item in ansible_facts.packages - - rhel9cis_firewall == 'nftables' - ansible.builtin.systemd: - name: "{{ item }}" - masked: true - loop: - - firewalld - - - name: "4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | firewalld" - when: - - item in ansible_facts.packages - - rhel9cis_firewall == 'firewalld' - ansible.builtin.systemd: - name: "{{ item }}" - masked: true - loop: - - nftables - - - name: "4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | package installed" - ansible.builtin.package: - name: "{{ rhel9cis_firewall }}" - state: installed - - - name: "4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | {{ rhel9cis_firewall }} started and enabled" # noqa name[template] - ansible.builtin.systemd: - name: "{{ rhel9cis_firewall }}" - enabled: true - state: started diff --git a/tasks/section_4/cis_4.2.1.x.yml b/tasks/section_4/cis_4.2.1.x.yml new file mode 100644 index 0000000..10e0ac2 --- /dev/null +++ b/tasks/section_4/cis_4.2.1.x.yml @@ -0,0 +1,216 @@ +--- + +- name: "4.2.1.1 | PATCH | Ensure rsyslog installed" + ansible.builtin.package: + name: rsyslog + state: present + when: + - "'rsyslog' not in ansible_facts.packages" + - rhel9cis_rule_4_2_1_1 + tags: + - level1-server + - level1-workstation + - patch + - rsyslog + - rule_4.2.1.1 + +- name: "4.2.1.2 | PATCH | Ensure rsyslog Service is enabled" + ansible.builtin.systemd: + name: rsyslog + enabled: true + when: + - rhel9cis_rule_4_2_1_2 + tags: + - level1-server + - level1-workstation + - patch + - rsyslog + - rule_4.2.1.2 + +- name: "4.2.1.3 | PATCH | Ensure journald is configured to send logs to rsyslog" + ansible.builtin.lineinfile: + path: /etc/systemd/journald.conf + regexp: "^#ForwardToSyslog=|^ForwardToSyslog=" + line: ForwardToSyslog=yes + notify: Restart rsyslog + when: + - rhel9cis_rule_4_2_1_3 + - rhel9cis_syslog == "rsyslog" + tags: + - level1-server + - level1-workstation + - patch + - rule_4.2.1.3 + +- name: "4.2.1.4 | PATCH | Ensure rsyslog default file permissions configured" + ansible.builtin.lineinfile: + path: /etc/rsyslog.conf + regexp: '^\$FileCreateMode' + line: '$FileCreateMode 0640' + notify: Restart rsyslog + when: + - rhel9cis_rule_4_2_1_4 + tags: + - level1-server + - level1-workstation + - patch + - rsyslog + - rule_4.2.1.4 + +- name: "4.2.1.5 | PATCH | Ensure logging is configured" + block: + - name: "4.2.1.5 | AUDIT | Ensure logging is configured | rsyslog current config message out" + ansible.builtin.shell: cat /etc/rsyslog.conf + changed_when: false + failed_when: false + check_mode: false + register: rhel_09_4_2_1_5_audit + + - name: "4.2.1.5 | AUDIT | Ensure logging is configured | rsyslog current config message out" + ansible.builtin.debug: + msg: + - "These are the current logging configurations for rsyslog, please review:" + - "{{ rhel_09_4_2_1_5_audit.stdout_lines }}" + + - name: "4.2.1.5 | PATCH | Ensure logging is configured | mail.* log setting" + ansible.builtin.blockinfile: + path: /etc/rsyslog.conf + marker: "# {mark} MAIL LOG SETTINGS - CIS benchmark - Ansible-lockdown" + block: | + # mail logging additions to meet CIS standards + mail.* -/var/log/mail + mail.info -/var/log/mail.info + mail.warning -/var/log/mail.warning + mail.err /var/log/mail.err + insertafter: '# Log all the mail messages in one place.' + notify: Restart rsyslog + when: rhel9cis_rsyslog_ansiblemanaged + + - name: "4.2.1.5 | PATCH | Ensure logging is configured | news.crit log setting" + ansible.builtin.blockinfile: + path: /etc/rsyslog.conf + state: present + marker: "# {mark} NEWS LOG SETTINGS - CIS benchmark - Ansible-lockdown" + block: | + # news logging additions to meet CIS standards + news.crit -/var/log/news/news.crit + news.notice -/var/log/news/news.crit + insertafter: '# Save news errors of level crit and higher in a special file.' + notify: Restart rsyslog + when: rhel9cis_rsyslog_ansiblemanaged + + - name: "4.2.1.5 | PATCH | Ensure logging is configured | Misc. log setting" + ansible.builtin.blockinfile: + path: /etc/rsyslog.conf + state: present + marker: "# {mark} MISC. LOG SETTINGS - CIS benchmark - Ansible-lockdown" + block: | + # misc. logging additions to meet CIS standards + *.=warning;*.=err -/var/log/warn + *.crit /var/log/warn + *.*;mail.none;news.none /var/log/messages + insertafter: '#### RULES ####' + notify: Restart rsyslog + when: rhel9cis_rsyslog_ansiblemanaged + + - name: "4.2.1.5 | PATCH | Ensure logging is configured | Local log settings" + ansible.builtin.blockinfile: + path: /etc/rsyslog.conf + state: present + marker: "#{mark} LOCAL LOG SETTINGS - CIS benchmark - Ansible-lockdown" + block: | + # local log settings to meet CIS standards + local0,local1.* -/var/log/localmessages + local2,local3.* -/var/log/localmessages + local4,local5.* -/var/log/localmessages + local6,local7.* -/var/log/localmessages + *.emrg :omusrmsg:* + insertafter: '#### RULES ####' + notify: Restart rsyslog + + - name: "4.2.1.5 | PATCH | Ensure logging is configured | Auth Settings" + ansible.builtin.blockinfile: + path: /etc/rsyslog.conf + state: present + marker: "#{mark} Auth SETTINGS - CIS benchmark - Ansible-lockdown" + block: | + # Private settings to meet CIS standards + auth,authpriv.* /var/log/secure + insertafter: '#### RULES ####' + notify: Restart rsyslog + + - name: "4.2.1.5 | PATCH | Ensure logging is configured | Cron Settings" + ansible.builtin.blockinfile: + path: /etc/rsyslog.conf + state: present + marker: "#{mark} Cron SETTINGS - CIS benchmark - Ansible-lockdown" + block: | + # Cron settings to meet CIS standards + cron.* /var/log/cron + insertafter: '#### RULES ####' + notify: Restart rsyslog + when: + - rhel9cis_rule_4_2_1_5 + tags: + - level1-server + - level1-workstation + - patch + - rsyslog + - rule_4.2.1.5 + +- name: "4.2.1.6 | PATCH | Ensure rsyslog is configured to send logs to a remote log host" + ansible.builtin.blockinfile: + path: /etc/rsyslog.conf + state: present + block: | + # target can be IP or FQDN + *.* action(type="omfwd" target="{{ rhel9cis_remote_log_host }}" port="{{ rhel9cis_remote_log_port }}" protocol="{{ rhel9cis_remote_log_protocol }}" action.resumeRetryCount="{{ rhel9cis_remote_log_retrycount }}" queue.type="LinkedList" queue.size="{{ rhel9cis_remote_log_queuesize }}") + insertafter: EOF + register: result + failed_when: + - result is failed + - result.rc != 257 + notify: Restart rsyslog + when: + - rhel9cis_rule_4_2_1_6 + - rhel9cis_remote_log_server + tags: + - level1-server + - level1-workstation + - patch + - rsyslog + - rule_4.2.1.6 + +- name: "4.2.1.7 | PATCH | Ensure rsyslog is not configured to recieve logs from a remote client" + block: + - name: "4.2.1.7 | PATCH | Ensure rsyslog is not configured to recieve logs from a remote client. | When not log host" + ansible.builtin.replace: + path: /etc/rsyslog.conf + regexp: '{{ item }}' + replace: '#\1' + notify: Restart rsyslog + loop: + - '^(\$ModLoad imtcp)' + - '^(\$InputTCPServerRun)' + - '^(module\(load="imtcp"\))' + - '^(input\(type="imtcp")' + when: not rhel9cis_system_is_log_server + + - name: "4.2.1.7 | PATCH | Ensure rsyslog is not configured to recieve logs from a remote clients. | When log host" + ansible.builtin.replace: + path: /etc/rsyslog.conf + regexp: '^#(.*{{ item }}.*)' + replace: '\1' + notify: Restart rsyslog + loop: + - 'ModLoad imtcp' + - 'InputTCPServerRun' + when: rhel9cis_system_is_log_server + when: + - rhel9cis_rule_4_2_1_7 + tags: + - level1-server + - level1-workstation + - patch + - rsyslog + - rule_4.2.1.7 diff --git a/tasks/section_4/cis_4.2.2.x.yml b/tasks/section_4/cis_4.2.2.x.yml new file mode 100644 index 0000000..2c9355b --- /dev/null +++ b/tasks/section_4/cis_4.2.2.x.yml @@ -0,0 +1,199 @@ +--- + +- name: "4.2.2.1.1 | PATCH | Ensure systemd-journal-remote is installed" + ansible.builtin.package: + name: systemd-journal-remote + state: present + when: + - rhel9cis_rule_4_2_2_1_1 + tags: + - level1-server + - level1-workstation + - manual + - patch + - journald + - rule_4.2.2.1.1 + +- name: "4.2.2.1.2 | PATCH | Ensure systemd-journal-remote is configured" + ansible.builtin.lineinfile: + path: /etc/systemd/journal-upload.conf + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + notify: Restart journald + loop: + - { regexp: 'URL=', line: 'URL={{ rhel9cis_journal_upload_url }}'} + - { regexp: 'ServerKeyFile=', line: 'ServerKeyFile={{ rhel9cis_journal_upload_serverkeyfile }}'} + - { regexp: 'ServerCertificateFile=', line: 'ServerCertificateFile={{ rhel9cis_journal_servercertificatefile }}'} + - { regexp: 'TrustedCertificateFile=', line: 'TrustedCertificateFile={{ rhel9cis_journal_trustedcertificatefile }}'} + when: + - rhel9cis_rule_4_2_2_1_2 + tags: + - level1-server + - level1-workstation + - manual + - patch + - journald + - rule_4.2.2.1.2 + +- name: "4.2.2.1.3 | PATCH | Ensure systemd-journal-remote is enabled" + ansible.builtin.systemd: + name: systemd-journal-upload + state: started + enabled: true + when: + - rhel9cis_system_is_log_server + - rhel9cis_rule_4_2_2_1_3 + tags: + - level1-server + - level1-workstation + - manual + - patch + - journald + - rule_4.2.2.1.3 + +- name: "4.2.2.1.4 | PATCH | Ensure journald is not configured to recieve logs from a remote client" + ansible.builtin.systemd: + name: systemd-journal-remote.socket + state: stopped + enabled: false + masked: true + when: + - not rhel9cis_system_is_log_server + - rhel9cis_rule_4_2_2_1_4 + tags: + - level1-server + - level1-workstation + - patch + - journald + - rule_4.2.2.1.4 + +- name: "4.2.2.2 | PATCH | Ensure journald service is enabled" + block: + - name: "4.2.2.2 | PATCH | Ensure journald service is enabled | Enable service" + ansible.builtin.systemd: + name: systemd-journald + state: started + enabled: true + + - name: "4.2.2.2 | AUDIT | Ensure journald service is enabled | Capture status" + ansible.builtin.shell: systemctl is-enabled systemd-journald.service + changed_when: false + failed_when: false + register: rhel9cis_4_2_2_2_status + + - name: "4.2.2.2 | AUDIT | Ensure journald service is enabled | Alert on bad status" + ansible.builtin.debug: + msg: + - "Warning!! The status of systemd-journald should be static and it is not. Please investigate" + when: "'static' not in rhel9cis_4_2_2_2_status.stdout" + + - name: "4.2.2.2 | AUDIT | Ensure journald service is enabled | Warn Count" + ansible.builtin.import_tasks: warning_facts.yml + when: "'static' not in rhel9cis_4_2_2_2_status.stdout" + vars: + warn_control_id: '4.2.2.2' + when: + - rhel9cis_rule_4_2_2_2 + tags: + - level1-server + - level1-workstation + - audit + - journald + - rule_4.2.2.2 + +- name: "4.2.2.3 | PATCH | Ensure journald is configured to compress large log files" + ansible.builtin.lineinfile: + path: /etc/systemd/journald.conf + regexp: "^#Compress=|^Compress=" + line: Compress=yes + notify: Restart journald + when: + - rhel9cis_rule_4_2_2_3 + tags: + - level1-server + - level1-workstation + - patch + - journald + - rule_4.2.2.3 + +- name: "4.2.2.4 | PATCH | Ensure journald is configured to write logfiles to persistent disk" + ansible.builtin.lineinfile: + path: /etc/systemd/journald.conf + regexp: "^#Storage=|^Storage=" + line: Storage=persistent + notify: Restart journald + when: + - rhel9cis_rule_4_2_2_4 + tags: + - level1-server + - level1-workstation + - patch + - journald + - rule_4.2.2.4 + +# This is counter to control 4.2.1.3?? +- name: "4.2.2.5 | PATCH | Ensure journald is not configured to send logs to rsyslog" + ansible.builtin.lineinfile: + path: /etc/systemd/journald.conf + regexp: "^ForwardToSyslog=" + line: "#ForwardToSyslog=yes" + notify: Restart journald + when: + - rhel9cis_rule_4_2_2_5 + tags: + - level1-server + - level2-workstation + - manual + - patch + - journald + - rule_4.2.2.5 + +- name: "4.2.2.6 | PATCH | Ensure journald log rotation is configured per site policy" + ansible.builtin.lineinfile: + path: /etc/systemd/journald.conf + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + notify: Restart journald + loop: + - { regexp: '^#SystemMaxUse=|^SystemMaxUse=', line: 'SystemMaxUse={{ rhel9cis_journald_systemmaxuse }}'} + - { regexp: '^#SystemKeepFree=|^SystemKeepFree=', line: 'SystemKeepFree={{ rhel9cis_journald_systemkeepfree }}' } + - { regexp: '^#RuntimeMaxUse=|^RuntimeMaxUse=', line: 'RuntimeMaxUse={{ rhel9cis_journald_runtimemaxuse }}'} + - { regexp: '^#RuntimeKeepFree=|^RuntimeKeepFree=', line: 'RuntimeKeepFree={{ rhel9cis_journald_runtimekeepfree }}'} + - { regexp: '^#MaxFileSec=|^MaxFileSec=', line: 'MaxFileSec={{ rhel9cis_journald_maxfilesec }}'} + when: + - rhel9cis_rule_4_2_2_6 + tags: + - level1-server + - level1-workstation + - manual + - patch + - journald + - rule_4.2.2.6 + +- name: "4.2.2.7 | AUDIT | Ensure journald default file permissions configured" + block: + - name: "4.2.2.7 | AUDIT | Ensure journald default file permissions configured | Check for override file" + ansible.builtin.stat: + path: /etc/tmpfiles.d/systemd.conf + register: rhel9cis_4_2_2_7_override + + - name: "4.2.2.7 | AUDIT | Ensure journald default file permissions configured | Set live file" + ansible.builtin.set_fact: + systemd_conf_file: /etc/tmpfiles.d/systemd.conf + when: rhel9cis_4_2_2_7_override.stat.exists + + - name: "4.2.2.7 | PATCH | Ensure journald default file permissions configured | Set permission" + ansible.builtin.lineinfile: + path: "{{ systemd_conf_file | default('/usr/lib/tmpfiles.d/systemd.conf') }}" + regexp: "^z \/var\/log\/journal\/%m\/system.journal (!?06(0|4)0) root" + line: 'z /var/log/journal/%m/system.journal 0640 root systemd-journal - -' + + when: + - rhel9cis_rule_4_2_2_7 + tags: + - level1-server + - level1-workstation + - manual + - patch + - journald + - rule_4.2.2.7 diff --git a/tasks/section_4/cis_4.2.3.yml b/tasks/section_4/cis_4.2.3.yml new file mode 100644 index 0000000..a391254 --- /dev/null +++ b/tasks/section_4/cis_4.2.3.yml @@ -0,0 +1,30 @@ +--- + +- name: "4.2.3 | PATCH | Ensure permissions on all logfiles are configured" + block: + - name: "4.2.3 | AUDIT | Ensure permissions on all logfiles are configured | find files" + ansible.builtin.find: + paths: "/var/log" + file_type: file + recurse: true + register: logfiles + + - name: "4.2.3 | PATCH | Ensure permissions on all logfiles are configured | change permissions" + ansible.builtin.file: + path: "{{ item.path }}" + mode: 0640 + loop: "{{ logfiles.files }}" + loop_control: + label: "{{ item.path }}" + when: + - item.path != "/var/log/btmp" + - item.path != "/var/log/utmp" + - item.path != "/var/log/wtmp" + when: + - rhel9cis_rule_4_2_3 + tags: + - level1-server + - level1-workstation + - patch + - logfiles + - rule_4.2.3 diff --git a/tasks/section_4/cis_4.2.x.yml b/tasks/section_4/cis_4.2.x.yml deleted file mode 100644 index 6e8eb3c..0000000 --- a/tasks/section_4/cis_4.2.x.yml +++ /dev/null @@ -1,43 +0,0 @@ ---- - -- name: "4.2.1 | AUDIT | Ensure firewalld drops unnecessary services and ports" - when: rhel9cis_rule_4_2_1 - tags: - - level1-server - - level1-workstation - - manual - - audit - - rule_4.2.1 - - NIST800-55_CA-9 - block: - - name: "4.2.1 | AUDIT | Ensure firewalld drops unnecessary services and ports | Get list of services and ports" - ansible.builtin.shell: "firewall-cmd --get-active-zones | awk '!/:/ {print $1}' | while read ZN; do firewall-cmd --list-all --zone=$ZN; done" - changed_when: false - failed_when: false - check_mode: false - register: discovered_services_and_ports - - - name: "4.2.1 | AUDIT | Ensure firewalld drops unnecessary services and ports | Show services and ports" - ansible.builtin.debug: - msg: - - "The items below are the services and ports that are accepted, please correct as needed" - - "{{ discovered_services_and_ports.stdout_lines }}" - -- name: "4.2.2 | PATCH | Ensure firewalld loopback traffic is configured | firewalld" - when: rhel9cis_rule_4_2_2 - tags: - - level1-server - - level1-workstation - - patch - - nftables - - rule_4.2.2 - - NIST800-55_CA-9 - ansible.posix.firewalld: - rich_rule: "{{ item }}" - zone: "{{ rhel9cis_default_zone }}" - permanent: true - immediate: true - state: enabled - loop: - - rule family="ipv4" source address="127.0.0.1" destination not address="127.0.0.1" drop - - rule family="ipv6" source address="::1" destination not address="::1" drop diff --git a/tasks/section_4/cis_4.3.x.yml b/tasks/section_4/cis_4.3.x.yml deleted file mode 100644 index 4398df2..0000000 --- a/tasks/section_4/cis_4.3.x.yml +++ /dev/null @@ -1,221 +0,0 @@ ---- - -- name: "OPTIONAL | PATCH | Create Table if doesn't exist and required" - when: - - rhel9cis_nft_tables_autonewtable - - rhel9cis_rule_4_3_1 - - rhel9cis_rule_4_3_2 - - rhel9cis_rule_4_3_3 - - rhel9cis_rule_4_3_4 - tags: always - ansible.builtin.command: "nft add table inet {{ rhel9cis_nft_tables_tablename }}" - changed_when: true - -- name: "4.3.1 | PATCH | Ensure nftables base chains exist" - when: rhel9cis_rule_4_3_1 - tags: - - level1-server - - level1-workstation - - patch - - nftables - - rule_4.3.1 - - NIST800-55_CA-9 - block: - - name: "4.3.1 | AUDIT | Ensure nftables base chains exist | Get current chains for INPUT" - ansible.builtin.shell: | - nft list ruleset | grep 'hook input' - changed_when: false - failed_when: false - register: discovered_nftables_input_chains - - - name: "4.3.1 | AUDIT | Ensure nftables base chains exist | Get current chains for FORWARD" - ansible.builtin.shell: | - nft list ruleset | grep 'hook forward' - changed_when: false - failed_when: false - register: discovered_nftables_forward_chains - - - name: "4.3.1 | AUDIT | Ensure nftables base chains exist | Get current chains for OUTPUT" - ansible.builtin.shell: | - nft list ruleset | grep 'hook output' - changed_when: false - failed_when: false - register: discovered_nftables_output_chains - - - name: "4.3.1 | AUDIT | Ensure nftables base chains exist | Display chains for review" - when: not rhel9cis_nft_tables_autochaincreate - ansible.builtin.debug: - msg: - - "Below are the current INPUT chains" - - "{{ discovered_nftables_input_chains.stdout_lines }}" - - "Below are the current FORWARD chains" - - "{{ discovered_nftables_forward_chains.stdout_lines }}" - - "Below are teh current OUTPUT chains" - - "{{ discovered_nftables_output_chains.stdout_lines }}" - - - name: "4.3.1 | PATCH | Ensure nftables base chains exist | Create chains if needed" - when: rhel9cis_nft_tables_autochaincreate - ansible.builtin.command: "{{ item }}" - changed_when: true - failed_when: false - loop: - - nft create chain inet "{{ rhel9cis_nft_tables_tablename }}" input { type filter hook input priority 0 \; } - - nft create chain inet "{{ rhel9cis_nft_tables_tablename }}" forward { type filter hook forward priority 0 \; } - - nft create chain inet "{{ rhel9cis_nft_tables_tablename }}" output { type filter hook output priority 0 \; } - -- name: "4.3.2 | PATCH | Ensure nftables established connections are configured" - when: rhel9cis_rule_4_3_2 - tags: - - level1-server - - level1-workstation - - patch - - nftables - - rule_4.3.2 - - NIST800-55_CA-9 - block: - - name: "4.3.2 | AUDIT | Ensure nftables established connections are configured | Gather incoming connection rules" - ansible.builtin.shell: | - nft list ruleset | awk '/hook input/,/}/' | grep -E 'ip protocol (tcp|udp|icmp) ct state' - changed_when: false - failed_when: false - register: discovered_nftables_inconnectionrule - - - name: "4.3.2 | AUDIT | Ensure nftables established connections are configured | Gather outbound connection rules" - ansible.builtin.shell: nft list ruleset | awk '/hook output/,/}/' | grep -E 'ip protocol (tcp|udp|icmp) ct state' - changed_when: false - failed_when: false - register: discovered_nftables_outconnectionrule - - - name: "4.3.2| PATCH | Ensure nftables established connections are configured | Add input tcp established accept policy" - when: '"ip protocol tcp ct state established accept" not in discovered_nftables_inconnectionrule.stdout' - ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip protocol tcp ct state established accept - changed_when: true - - - name: "4.3.2 | PATCH | Ensure nftables established connections are configured | Add input udp established accept policy" - when: '"ip protocol udp ct state established accept" not in discovered_nftables_inconnectionrule.stdout' - ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip protocol udp ct state established accept - changed_when: true - - - name: "4.3.2 | PATCH | Ensure nftables established connections are configured | Add input icmp established accept policy" - when: '"ip protocol icmp ct state established accept" not in discovered_nftables_inconnectionrule.stdout' - ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip protocol icmp ct state established accept - changed_when: true - - - name: "4.3.2 | PATCH | Ensure nftables established connections are configured | Add output tcp new, related, established accept policy" - when: '"ip protocol tcp ct state established,related,new accept" not in discovered_nftables_outconnectionrule.stdout' - ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" output ip protocol tcp ct state new,related,established accept - changed_when: true - - - name: "4.3.2 | PATCH | Ensure nftables established connections are configured | Add output udp new, related, established accept policy" - when: '"ip protocol udp ct state established,related,new accept" not in discovered_nftables_outconnectionrule.stdout' - ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" output ip protocol udp ct state new,related,established accept - changed_when: true - - - name: "4.3.2 | PATCH | Ensure nftables established connections are configured | Add output icmp new, related, established accept policy" - when: '"ip protocol icmp ct state established,related,new accept" not in discovered_nftables_outconnectionrule.stdout' - ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" output ip protocol icmp ct state new,related,established accept - changed_when: true - -- name: "4.3.3 | PATCH | Ensure nftables default deny firewall policy" - when: rhel9cis_rule_4_3_3 - tags: - - level1-server - - level1-workstation - - patch - - nftables - - rule_4.3.3 - - NIST800-55_CA-9 - block: - - name: "4.3.3 | AUDIT | Ensure nftables default deny firewall policy | Check for hook input deny policy" - ansible.builtin.shell: | - nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'hook input' - failed_when: false - changed_when: false - register: discovered_nftables_inputpolicy - - - name: "4.3.3 | AUDIT | Ensure nftables default deny firewall policy | Check for hook forward deny policy" - ansible.builtin.shell: | - nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'hook forward' - failed_when: false - changed_when: false - register: discovered_nftables_forwardpolicy - - - name: "4.3.3 | AUDIT | Ensure nftables default deny firewall policy | Check for hook output deny policy" - ansible.builtin.shell: | - nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'hook output' - failed_when: false - changed_when: false - register: discovered_nftables_outputpolicy - - - name: "4.3.3 | AUDIT | Ensure nftables default deny firewall policy | Check for SSH allow" - ansible.builtin.shell: | - nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'ssh' - failed_when: false - changed_when: false - register: discovered_nftables_sshallowcheck - - - name: "4.3.3 | PATCH | Ensure nftables default deny firewall policy | Enable SSH traffic" - when: '"tcp dport ssh accept" not in discovered_nftables_sshallowcheck.stdout' - ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input tcp dport ssh accept - changed_when: true - - - name: "4.3.3 | PATCH | Ensure nftables default deny firewall policy | Set hook input deny policy" - when: '"type filter hook input priority 0; policy drop;" not in discovered_nftables_inputpolicy.stdout' - ansible.builtin.command: nft chain inet "{{ rhel9cis_nft_tables_tablename }}" input { policy drop \; } - changed_when: true - - - name: "4.3.3 | PATCH | Ensure nftables default deny firewall policy | Create hook forward deny policy" - when: '"type filter hook forward priority 0; policy drop;" not in discovered_nftables_forwardpolicy.stdout' - ansible.builtin.command: nft chain inet "{{ rhel9cis_nft_tables_tablename }}" forward { policy drop \; } - changed_when: true - - - name: "4.3.3 | PATCH | Ensure nftables default deny firewall policy | Create hook output deny policy" - when: '"type filter hook output priority 0; policy drop;" not in discovered_nftables_outputpolicy.stdout' - ansible.builtin.command: nft chain inet "{{ rhel9cis_nft_tables_tablename }}" output { policy drop \; } - changed_when: true - -- name: "4.3.4 | PATCH | Ensure nftables loopback traffic is configured" - when: rhel9cis_rule_4_3_4 - tags: - - level1-server - - level1-workstation - - patch - - nftables - - rule_4.3.4 - - NIST800-55_CA-9 - block: - - name: "4.3.4 | AUDIT | Ensure nftables loopback traffic is configured | Gather iif lo accept existence | nftables" - ansible.builtin.shell: | - nft list ruleset | awk '/hook input/,/}/' | grep 'iif "lo" accept' - changed_when: false - failed_when: false - register: discovered_nftables_iiflo - - - name: "4.3.4 | AUDIT | Ensure nftables loopback traffic is configured | Gather ip saddr existence | nftables" - ansible.builtin.shell: | - nft list ruleset | awk '/hook input/,/}/' | grep 'ip saddr' - changed_when: false - failed_when: false - register: discovered_nftables_ipsaddr - - - name: "4.3.4 | AUDIT | Ensure nftables loopback traffic is configured | Gather ip6 saddr existence | nftables" - ansible.builtin.shell: | - nft list ruleset | awk '/hook input/,/}/' | grep 'ip6 saddr' - changed_when: false - failed_when: false - register: discovered_nftables_ip6saddr - - - name: "4.3.4 | PATCH | Ensure nftables loopback traffic is configured | Set iif lo accept rule | nftables" - when: '"iif \"lo\" accept" not in discovered_nftables_iiflo.stdout' - ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input iif lo accept - changed_when: true - - - name: "4.3.4 | PATCH | Ensure nftables loopback traffic is configured | Set ip sddr rule | nftables" - when: '"ip saddr 127.0.0.0/8 counter packets 0 bytes 0 drop" not in discovered_nftables_ipsaddr.stdout' - ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip saddr 127.0.0.0/8 counter drop - changed_when: true - - - name: "4.3.4 | PATCH | Ensure nftables loopback traffic is configured | Set ip6 saddr rule | nftables" - when: '"ip6 saddr ::1 counter packets 0 bytes 0 drop" not in discovered_nftables_ip6saddr.stdout' - ansible.builtin.command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip6 saddr ::1 counter drop - changed_when: true diff --git a/tasks/section_4/cis_4.3.yml b/tasks/section_4/cis_4.3.yml new file mode 100644 index 0000000..be17c70 --- /dev/null +++ b/tasks/section_4/cis_4.3.yml @@ -0,0 +1,55 @@ +--- + +- name: "4.3 | PATCH | Ensure logrotate is configured" + block: + - name: "4.3 | PATCH | Ensure logrotate is configured | installed" + ansible.builtin.package: + name: rsyslog-logrotate + state: present + + - name: "4.3 | PATCH | Ensure logrotate is configured | scheduled" + ansible.builtin.systemd: + name: logrotate.timer + state: started + enabled: true + + - name: "4.3 | PATCH | Ensure logrotate is configured | set default conf" + ansible.builtin.replace: + path: "/etc/logrotate.conf" + regexp: '^(\s*)(daily|weekly|monthly|yearly)$' + replace: "\\1{{ rhel9cis_logrotate }}" + + - name: "4.3 | AUDIT | Ensure logrotate is configured | Get non default logrotate settings" + ansible.builtin.find: + paths: /etc/logrotate.d/ + contains: '^(\s*)(?!{{ rhel9cis_logrotate }})(daily|weekly|monthly|yearly)$' + register: log_rotates + + - name: "4.3 | AUDIT | Ensure logrotate is configured" + block: + - name: "4.3 | AUDIT | Ensure logrotate is configured | generate file list" + ansible.builtin.set_fact: + logrotate_non_def_conf: "{{ log_rotates.files | map(attribute='path') | join (', ') }}" + + - name: "4.3 | AUDIT | Ensure logrotate is configured | List configured files" + ansible.builtin.debug: + msg: | + "Warning!! The following files are not covered by default logrotate settings ensure they match site policy" + "{{ logrotate_non_def_conf }}" + loop: "{{ log_rotates.files }}" + + - name: "4.3 | AUDIT | Ensure logrotate is configured | Warning count" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '4.3' + when: log_rotates.matched > 0 + + when: + - rhel9cis_rule_4_3 + tags: + - level1-server + - level1-workstation + - manual + - patch + - logrotate + - rule_4.3 diff --git a/tasks/section_4/main.yml b/tasks/section_4/main.yml index 5acc222..285a2f3 100644 --- a/tasks/section_4/main.yml +++ b/tasks/section_4/main.yml @@ -1,15 +1,29 @@ --- -- name: "SECTION | 4.1.x | Configure a firewall" - ansible.builtin.import_tasks: - file: cis_4.1.x.yml +- name: "SECTION | 4.1 | Configure System Accounting (auditd)" + ansible.builtin.import_tasks: cis_4.1.1.x.yml + when: + - not system_is_container -- name: "SECTION | 4.2.x | Configure FirewallD" - when: rhel9cis_firewall == "firewalld" - ansible.builtin.import_tasks: - file: cis_4.2.x.yml +- name: "SECTION | 4.1.2 | Configure Data Retention" + ansible.builtin.import_tasks: cis_4.1.2.x.yml -- name: "SECTION | 4.3.x | Configure nftables" - when: rhel9cis_firewall == "nftables" - ansible.builtin.import_tasks: - file: cis_4.3.x.yml +- name: "SECTION | 4.1.3 | Configure Auditd rules" + ansible.builtin.import_tasks: cis_4.1.3.x.yml + +- name: "SECTION | 4.1.4 | Configure Audit files" + ansible.builtin.import_tasks: cis_4.1.4.x.yml + +- name: "SECTION | 4.2 | Configure Logging" + ansible.builtin.import_tasks: cis_4.2.1.x.yml + when: rhel9cis_syslog == 'rsyslog' + +- name: "SECTION | 4.2.2 | Configure journald" + ansible.builtin.import_tasks: cis_4.2.2.x.yml + when: rhel9cis_syslog == 'journald' + +- name: "SECTION | 4.2.3 | Configure logile perms" + ansible.builtin.import_tasks: cis_4.2.3.yml + +- name: "SECTION | 4.3 | Configure logrotate" + ansible.builtin.import_tasks: cis_4.3.yml diff --git a/tasks/section_5/cis_5.1.x.yml b/tasks/section_5/cis_5.1.x.yml index dc450ea..f897c6c 100644 --- a/tasks/section_5/cis_5.1.x.yml +++ b/tasks/section_5/cis_5.1.x.yml @@ -1,539 +1,163 @@ --- -- name: "5.1.1 | PATCH | Ensure permissions on /etc/ssh/sshd_config are configured" - when: rhel9cis_rule_5_1_1 +- name: "5.1.1 | PATCH | Ensure cron daemon is enabled" + ansible.builtin.service: + name: crond + enabled: true + when: + - rhel9cis_rule_5_1_1 tags: - - level1-server - - level1-workstation - - patch - - sshd - - permissions - - rule_5.1.1 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 + - level1-server + - level1-workstation + - patch + - cron + - rule_5.1.1 + +- name: "5.1.2 | PATCH | Ensure permissions on /etc/crontab are configured" ansible.builtin.file: - path: "/etc/ssh/sshd_config" - owner: root - group: root - mode: 'go-rwx' - -- name: "5.1.2 | PATCH | Ensure permissions on SSH private host key files are configured" - when: rhel9cis_rule_5_1_2 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - permissions - - rule_5.1.2 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - block: - - name: "5.1.2 | AUDIT | Ensure permissions on SSH private host key files are configured | Find the SSH private host keys" - ansible.builtin.find: - paths: /etc/ssh - patterns: 'ssh_host_*_key' - recurse: true - file_type: any - register: discovered_ssh_private_host_key - - - name: "5.1.2 | PATCH | Ensure permissions on SSH private host key files are configured | Set permissions on SSH private host keys" - ansible.builtin.file: - path: "{{ item.path }}" - owner: root - group: "{{ 'ssh_keys' if (item.gr_name == 'ssh_keys') else 'root' }}" - mode: "{{ 'u-x,g-wx,o-rwx' if (item.gr_name == 'ssh_keys') else 'u-x,go-rwx' }}" - loop: "{{ discovered_ssh_private_host_key.files }}" - loop_control: - label: "{{ item.path }}" - -- name: "5.1.3 | PATCH | Ensure permissions on SSH public host key files are configured" - when: rhel9cis_rule_5_1_3 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - block: - - name: "5.1.3 | AUDIT | Ensure permissions on SSH public host key files are configured | Find the SSH public host keys" - ansible.builtin.find: - paths: /etc/ssh - patterns: 'ssh_host_*_key.pub' - recurse: true - file_type: any - register: discovered_ssh_public_host_key - - - name: "5.1.3 | PATCH | Ensure permissions on SSH public host key files are configured | Set permissions on SSH public host keys" - ansible.builtin.file: - path: "{{ item.path }}" - owner: root - group: root - mode: 'u-x,go-wx' - loop: "{{ discovered_ssh_public_host_key.files }}" - loop_control: - label: "{{ item.path }}" - -- name: "5.1.4 | PATCH | Ensure sshd Ciphers are configured" + path: /etc/crontab + owner: root + group: root + mode: 0600 when: - - rhel9cis_rule_5_1_4 - - "'NO-SSHWEAKCIPHERS' not in rhel9cis_crypto_policy_module" - - rhel9cis_crypto_policy_ansiblemanaged + - rhel9cis_rule_5_1_2 tags: - - level1-server - - level1-workstation - - automated - - patch - - crypto - - rule_5.1.4 - - NIST800-53R5_SC-8 - block: - - name: "5.1.4 | PATCH | Ensure sshd Ciphers are configured | Add submodule exclusion" - ansible.builtin.template: - src: etc/crypto-policies/policies/modules/NO-SSHWEAKCIPHERS.pmod.j2 - dest: /etc/crypto-policies/policies/modules/NO-SSHWEAKCIPHERS.pmod - owner: root - group: root - mode: 'g-wx,o-rwx' - notify: - - Update Crypto Policy - - Set Crypto Policy + - level1-server + - level1-workstation + - patch + - cron + - rule_5.1.2 - - name: "5.1.4 | PATCH | Ensure sshd Ciphers are configured | submodule to crypto policy modules" - ansible.builtin.set_fact: - rhel9cis_crypto_policy_module: "{{ rhel9cis_crypto_policy_module + ':NO-SSHWEAKCIPHERS' }}" - -- name: "5.1.5 | PATCH | Ensure sshd KexAlgorithms is configured" +- name: "5.1.3 | PATCH | Ensure permissions on /etc/cron.hourly are configured" + ansible.builtin.file: + path: /etc/cron.hourly + state: directory + owner: root + group: root + mode: 0700 when: - - rhel9cis_rule_5_1_5 - - "'NO-SHA1' not in rhel9cis_crypto_policy_module" - - rhel9cis_crypto_policy_ansiblemanaged + - rhel9cis_rule_5_1_3 tags: - - level1-server - - level1-workstation - - automated - - patch - - crypto - - rule_5.1.5 - - NIST800-53R5_SC-6 - block: - - name: "5.1.5 | PATCH | Ensure sshd KexAlgorithms is configured | Add submodule exclusion" - ansible.builtin.template: - src: etc/crypto-policies/policies/modules/NO-SHA1.pmod.j2 - dest: /etc/crypto-policies/policies/modules/NO-SHA1.pmod - owner: root - group: root - mode: 'g-wx,o-rwx' - notify: - - Update Crypto Policy - - Set Crypto Policy + - level1-server + - level1-workstation + - patch + - cron + - rule_5.1.3 - - name: "5.1.5 | PATCH | Ensure sshd KexAlgorithms is configured | submodule to crypto policy modules" - ansible.builtin.set_fact: - rhel9cis_crypto_policy_module: "{{ rhel9cis_crypto_policy_module + ':NO-SHA1' }}" - -- name: "5.1.6 | PATCH | Ensure sshd KexAlgorithms is configured" +- name: "5.1.4 | PATCH | Ensure permissions on /etc/cron.daily are configured" + ansible.builtin.file: + path: /etc/cron.daily + state: directory + owner: root + group: root + mode: 0700 when: - - rhel9cis_rule_5_1_6 - - "'NO-SSHWEAKMACS' not in rhel9cis_crypto_policy_module" - - rhel9cis_crypto_policy_ansiblemanaged + - rhel9cis_rule_5_1_4 tags: - - level1-server - - level1-workstation - - automated - - patch - - crypto - - rule_5.1.6 - - NIST800-53R5_SC-6 + - level1-server + - level1-workstation + - patch + - cron + - rule_5.1.4 + +- name: "5.1.5 | PATCH | Ensure permissions on /etc/cron.weekly are configured" + ansible.builtin.file: + path: /etc/cron.weekly + state: directory + owner: root + group: root + mode: 0700 + when: + - rhel9cis_rule_5_1_5 + tags: + - level1-server + - level1-workstation + - patch + - rule_5.1.5 + +- name: "5.1.6 | PATCH | Ensure permissions on /etc/cron.monthly are configured" + ansible.builtin.file: + path: /etc/cron.monthly + state: directory + owner: root + group: root + mode: 0700 + when: + - rhel9cis_rule_5_1_6 + tags: + - level1-server + - level1-workstation + - patch + - rule_5.1.6 + +- name: "5.1.7 | PATCH | Ensure permissions on /etc/cron.d are configured" + ansible.builtin.file: + path: /etc/cron.d + state: directory + owner: root + group: root + mode: 0700 + when: + - rhel9cis_rule_5_1_7 + tags: + - level1-server + - level1-workstation + - patch + - cron + - rule_5.1.7 + +- name: "5.1.8 | PATCH | Ensure cron is restricted to authorized users" block: - - name: "5.1.6 | PATCH | Ensure sshd KexAlgorithms is configured | Add submodule exclusion" - ansible.builtin.template: - src: etc/crypto-policies/policies/modules/NO-SSHWEAKMACS.pmod.j2 - dest: /etc/crypto-policies/policies/modules/NO-SSHWEAKMACS.pmod - owner: root - group: root - mode: 'g-wx,o-rwx' - notify: - - Update Crypto Policy - - Set Crypto Policy + - name: "5.1.8 | PATCH | Ensure cron is restricted to authorized users | Remove cron.deny" + ansible.builtin.file: + path: /etc/cron.deny + state: absent - - name: "5.1.6 | PATCH | Ensure sshd KexAlgorithms is configured | submodule to crypto policy modules" - ansible.builtin.set_fact: - rhel9cis_crypto_policy_module: "{{ rhel9cis_crypto_policy_module + ':' + 'NO-SSHWEAKMACS' }}" + - name: "5.1.8 | PATCH | Ensure cron is restricted to authorized users | Check if cron.allow exists" + ansible.builtin.stat: + path: "/etc/cron.allow" + register: rhel9cis_5_1_8_cron_allow_state -- name: "5.1.7 | PATCH | Ensure sshd access is configured" - when: rhel9cis_rule_5_1_7 + - name: "5.1.8 | PATCH | Ensure cron is restricted to authorized users | Ensure cron.allow is restricted to authorized users" + ansible.builtin.file: + path: /etc/cron.allow + state: '{{ "file" if rhel9cis_5_1_8_cron_allow_state.stat.exists else "touch" }}' + owner: root + group: root + mode: 0600 + when: + - rhel9cis_rule_5_1_8 tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.7 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 + - level1-server + - level1-workstation + - patch + - cron + - rule_5.1.8 + +- name: "5.1.9 | PATCH | Ensure at is restricted to authorized users" block: - - name: "5.1.7 | PATCH | Ensure sshd access is configured | Add line to sshd_config for allowusers" - when: "rhel9cis_sshd_allowusers | length > 0" - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: "^AllowUsers" - line: "AllowUsers {{ rhel9cis_sshd_allowusers }}" - validate: sshd -t -f %s - notify: Restart sshd + - name: "5.1.9 | PATCH | Ensure at is restricted to authorized users | Remove at.deny" + ansible.builtin.file: + path: /etc/at.deny + state: absent - - name: "5.1.7 | PATCH | Ensure sshd access is configured | Add line to sshd_config for allowgroups" - when: "rhel9cis_sshd_allowgroups | length > 0" - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: "^AllowGroups" - line: "AllowGroups {{ rhel9cis_sshd_allowgroups }}" - validate: sshd -t -f %s - notify: Restart sshd + - name: "5.1.9 | PATCH | Ensure at is restricted to authorized users | Check if at.allow exists" + ansible.builtin.stat: + path: "/etc/at.allow" + register: rhel9cis_5_1_9_at_allow_state - - name: "5.1.7 | PATCH | Ensure sshd access is configured | Add line to sshd_config for denyusers" - when: "rhel9cis_sshd_denyusers | length > 0" - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: "^DenyUsers" - line: "DenyUsers {{ rhel9cis_sshd_denyusers }}" - insertbefore: "^Match" - firstmatch: true - validate: sshd -t -f %s - notify: Restart sshd - - - name: "5.1.7 | PATCH | Ensure sshd access is configured | Add line to sshd_config for denygroups" - when: "rhel9cis_sshd_denygroups | length > 0" - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: "^DenyGroups" - line: "DenyGroups {{ rhel9cis_sshd_denygroups }}" - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.8 | PATCH | Ensure sshd Banner is configured" - when: rhel9cis_rule_5_1_8 + - name: "5.1.9 | PATCH | Ensure at is restricted to authorized users | Ensure at.allow is restricted to authorized users" + ansible.builtin.file: + path: /etc/at.allow + state: '{{ "file" if rhel9cis_5_1_9_at_allow_state.stat.exists else "touch" }}' + owner: root + group: root + mode: 0600 + when: + - rhel9cis_rule_5_1_9 tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.8 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: '^Banner' - line: 'Banner /etc/issue.net' - -- name: "5.1.9 | PATCH | Ensure sshd ClientAliveInterval and ClientAliveCountMax are configured" - when: rhel9cis_rule_5_1_9 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.9 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - block: - - name: "5.1.9 | PATCH | Ensure sshd ClientAliveInterval and ClientAliveCountMax are configured | Add line in sshd_config for ClientAliveInterval" - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: '^ClientAliveInterval' - line: "ClientAliveInterval {{ rhel9cis_sshd_clientaliveinterval }}" - validate: sshd -t -f %s - notify: Restart sshd - - - name: "5.1.9 | PATCH | Ensure sshd ClientAliveInterval and ClientAliveCountMax are configured | Ensure SSH ClientAliveCountMax set to <= 3" - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: '^ClientAliveCountMax' - line: "ClientAliveCountMax {{ rhel9cis_sshd_clientalivecountmax }}" - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.10 | PATCH | Ensure sshd DisableForwarding is enabled" - when: rhel9cis_rule_5_1_10 - tags: - - level2-server - - level1-workstation - - patch - - sshd - - rule_5.1.10 - - NIST800-53R5_CM-7 - block: - - name: "5.1.10 | PATCH | Ensure sshd DisableForwarding is enabled | config file" - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: ^(#|)\s*DisableForwarding - line: 'DisableForwarding yes' - validate: sshd -t -f %s - notify: Restart sshd - - - name: "5.1.10 | PATCH | Ensure sshd DisableForwarding is enabled | override" - when: prelim_sshd_50_redhat_file.stat.exists - ansible.builtin.lineinfile: - path: /etc/ssh/sshd_config.d/50-redhat.conf - regexp: (?i)^(#|)\s*X11Forwarding - line: 'X11Forwarding {{ rhel9cis_sshd_x11forwarding }}' - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.11 | PATCH | Ensure sshd GSSAPIAuthentication is disabled" - when: rhel9cis_rule_5_1_11 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.11 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - block: - - name: "5.1.11 | PATCH | Ensure sshd GSSAPIAuthentication is disabled | redhat file" - when: prelim_sshd_50_redhat_file.stat.exists - ansible.builtin.lineinfile: - path: /etc/ssh/sshd_config.d/50-redhat.conf - regexp: (?i)^(#|)\s*GSSAPIAuthentication - line: GSSAPIAuthentication no - validate: sshd -t -f %s - notify: Restart sshd - - - name: "5.1.11 | PATCH | Ensure sshd GSSAPIAuthentication is disabled | ssh config" - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: (?i)^(#|)\s*GSSAPIAuthentication - line: GSSAPIAuthentication no - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.12 | PATCH | Ensure sshd HostbasedAuthentication is disabled" - when: rhel9cis_rule_5_1_12 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.12 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: (?i)^(#|)\s*HostbasedAuthentication - line: 'HostbasedAuthentication no' - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.13 | PATCH | Ensure sshd IgnoreRhosts is enabled" - when: rhel9cis_rule_5_1_13 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.13 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: (?i)^(#|)\s*IgnoreRhosts - line: 'IgnoreRhosts yes' - insertbefore: "^Match" - firstmatch: true - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.14 | PATCH | Ensure sshd LoginGraceTime is set to one minute or less" - when: rhel9cis_rule_5_1_14 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.14 - - NIST800-53R5_CM-6 - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: (?i)^(#|)\s*LoginGraceTime - line: "LoginGraceTime {{ rhel9cis_sshd_logingracetime }}" - insertbefore: "^Match" - firstmatch: true - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.15 | PATCH | Ensure sshd LogLevel is appropriate" - when: rhel9cis_rule_5_1_15 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.15 - - NIST800-53R5_AU-3 - - NIST800-53R5_AU-12 - - NIST800-53R5_SI-5 - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: (?i)^(#|)\s*LogLevel - line: 'LogLevel {{ rhel9cis_ssh_loglevel }}' - insertbefore: "^Match" - firstmatch: true - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.16 | PATCH | Ensure sshd MaxAuthTries is set to 4 or less" - when: rhel9cis_rule_5_1_16 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.16 - - NIST800-53R5_AU-3 - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: '^(#)?MaxAuthTries \d' - line: 'MaxAuthTries {{ rhel9cis_ssh_maxauthtries }}' - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.17 | PATCH | Ensure sshd MaxStartups is configured" - when: rhel9cis_rule_5_1_17 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.17 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: (?i)^(#|)\s*MaxStartups - line: 'MaxStartups {{ rhel9cis_ssh_maxstartups }}' - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.18 | PATCH | Ensure SSH MaxSessions is set to 10 or less" - when: rhel9cis_rule_5_1_18 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.18 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: (?i)^(#|)\s*MaxSessions - line: 'MaxSessions {{ rhel9cis_ssh_maxsessions }}' - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.19 | PATCH | Ensure sshd PermitEmptyPasswords is disabled" - when: rhel9cis_rule_5_1_19 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.19 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: (?i)^(#|)\s*PermitEmptyPasswords - line: 'PermitEmptyPasswords no' - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.20 | PATCH | Ensure sshd PermitRootLogin is disabled" - when: rhel9cis_rule_5_1_20 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.20 - - NIST800-53R5_AC-6 - block: - - name: "5.1.20 | PATCH | Ensure sshd PermitRootLogin is disabled | config file" - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: (?i)^(#|)\s*PermitRootLogin - line: 'PermitRootLogin no' - validate: sshd -t -f %s - notify: Restart sshd - - - name: "5.1.20 | PATCH | Ensure sshd PermitRootLogin is disabled | override file" - ansible.builtin.file: - path: /etc/ssh/sshd_config.d/01-permitrootlogin.conf - state: absent - notify: Restart sshd - -- name: "5.1.21 | PATCH | Ensure sshd PermitUserEnvironment is disabled" - when: rhel9cis_rule_5_1_21 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.21 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: (?i)^(#|)\s*PermitUserEnvironment - line: 'PermitUserEnvironment no' - validate: sshd -t -f %s - notify: Restart sshd - -- name: "5.1.22 | PATCH | Ensure SSH PAM is enabled" - when: rhel9cis_rule_5_1_22 - tags: - - level1-server - - level1-workstation - - patch - - sshd - - rule_5.1.22 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - ansible.builtin.lineinfile: - path: "{{ rhel9cis_sshd_config_file }}" - regexp: (?i)^(#|)\s*UsePAM - line: 'UsePAM yes' - validate: sshd -t -f %s - notify: Restart sshd + - level1-server + - level1-workstation + - patch + - cron + - rule_5.1.9 diff --git a/tasks/section_5/cis_5.2.x.yml b/tasks/section_5/cis_5.2.x.yml index 3d57dbf..9054afd 100644 --- a/tasks/section_5/cis_5.2.x.yml +++ b/tasks/section_5/cis_5.2.x.yml @@ -1,158 +1,374 @@ --- -- name: "5.2.1 | PATCH | Ensure sudo is installed" - when: rhel9cis_rule_5_2_1 +- name: "5.2.1 | Ensure permissions on /etc/ssh/sshd_config are configured" + ansible.builtin.file: + path: "/etc/ssh/sshd_config" + owner: root + group: root + mode: 0600 + when: + - rhel9cis_rule_5_2_1 tags: - - level1-server - - level1-workstation - - patch - - sudo - - rule_5.2.1 - - NIST800-53R5_AC-6 - ansible.builtin.package: - name: sudo - state: present + - level1-server + - level1-workstation + - patch + - ssh + - permissions + - rule_5.2.1 -- name: "5.2.2 | PATCH | Ensure sudo commands use pty" - when: rhel9cis_rule_5_2_2 +- name: "5.2.2 | PATCH | Ensure permissions on SSH private host key files are configured" + block: + - name: "5.2.2 | AUDIT | Ensure permissions on SSH private host key files are configured | Find the SSH private host keys" + ansible.builtin.find: + paths: /etc/ssh + patterns: 'ssh_host_*_key' + recurse: true + file_type: any + register: rhel9cis_5_2_2_ssh_private_host_key + + - name: "5.2.2 | PATCH | Ensure permissions on SSH private host key files are configured | Set permissions on SSH private host keys" + ansible.builtin.file: + path: "{{ item.path }}" + owner: root + group: root + mode: 0600 + loop: "{{ rhel9cis_5_2_2_ssh_private_host_key.files }}" + loop_control: + label: "{{ item.path }}" + when: + - rhel9cis_rule_5_2_2 tags: - - level1-server - - level1-workstation - - patch - - sudo - - rule_5.2.2 - - NIST800-53R5_AC-6 + - level1-server + - level1-workstation + - patch + - ssh + - permissions + - rule_5.2.2 + +- name: "5.2.3 | PATCH | Ensure permissions on SSH public host key files are configured" + block: + - name: "5.2.3 | AUDIT | Ensure permissions on SSH public host key files are configured | Find the SSH public host keys" + ansible.builtin.find: + paths: /etc/ssh + patterns: 'ssh_host_*_key.pub' + recurse: true + file_type: any + register: rhel9cis_5_2_3_ssh_public_host_key + + - name: "5.2.3 | PATCH | Ensure permissions on SSH public host key files are configured | Set permissions on SSH public host keys" + ansible.builtin.file: + path: "{{ item.path }}" + owner: root + group: root + mode: 0644 + loop: "{{ rhel9cis_5_2_3_ssh_public_host_key.files }}" + loop_control: + label: "{{ item.path }}" + when: + - rhel9cis_rule_5_2_3 + tags: + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.3 + +- name: "5.2.4 | PATCH | Ensure SSH access is limited" + block: + - name: "5.2.4 | PATCH | Ensure SSH access is limited | Add line to sshd_config for allowusers" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^AllowUsers" + line: "AllowUsers {{ rhel9cis_sshd['allowusers'] }}" + validate: sshd -t -f %s + notify: Restart sshd + when: "rhel9cis_sshd['allowusers']|default('') | length > 0" + + - name: "5.2.4 | PATCH | Ensure SSH access is limited | Add line to sshd_config for allowgroups" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^AllowGroups" + line: "AllowGroups {{ rhel9cis_sshd['allowgroups'] }}" + validate: sshd -t -f %s + notify: Restart sshd + when: "rhel9cis_sshd['allowgroups']|default('') | length > 0" + + - name: "5.2.4 | PATCH | Ensure SSH access is limited | Add line to sshd_config for denyusers" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^DenyUsers" + line: "DenyUsers {{ rhel9cis_sshd['denyusers'] }}" + validate: sshd -t -f %s + notify: Restart sshd + when: "rhel9cis_sshd['denyusers']|default('') | length > 0" + + - name: "5.2.4 | PATCH | Ensure SSH access is limited | Add line to sshd_config for denygroups" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^DenyGroups" + line: "DenyGroups {{ rhel9cis_sshd['denygroups'] }}" + validate: sshd -t -f %s + notify: Restart sshd + when: "rhel9cis_sshd['denygroups']|default('') | length > 0" + when: + - rhel9cis_rule_5_2_4 + tags: + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.4 + +- name: "5.2.5 | PATCH | Ensure SSH LogLevel is appropriate" ansible.builtin.lineinfile: - path: /etc/sudoers - line: "Defaults use_pty" - validate: '/usr/sbin/visudo -cf %s' - -- name: "5.2.3 | PATCH | Ensure sudo log file exists" - when: rhel9cis_rule_5_2_3 + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^#LogLevel|^LogLevel" + line: 'LogLevel {{ rhel9cis_ssh_loglevel }}' + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_5 tags: - - level1-server - - level1-workstation - - patch - - sudo - - rule_5.2.3 - - NIST800-53R5_AU-3 - - NIST800-53R5_AU-12 + - level1-server + - level1-workstation + - patch + - sshs + - rule_5.2.5 + +- name: "5.2.6 | PATCH | Ensure SSH PAM is enabled" ansible.builtin.lineinfile: - path: /etc/sudoers - regexp: '^Defaults logfile=' - line: 'Defaults logfile="{{ rhel9cis_sudolog_location }}"' - validate: '/usr/sbin/visudo -cf %s' - -- name: "5.2.4 | PATCH | Ensure users must provide password for escalation" - when: rhel9cis_rule_5_2_4 + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^#UsePAM|^UsePAM" + line: 'UsePAM yes' + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_6 tags: - - level2-server - - level2-workstation - - patch - - sudo - - rule_5.2.4 - - NIST800-53R5_AC-6 - block: - - name: "5.2.4 | AUDIT | Ensure users must provide password for escalation | Discover accts with NOPASSWD" - ansible.builtin.shell: grep -Ei '(nopasswd)' /etc/sudoers /etc/sudoers.d/* | cut -d':' -f1 - become: true - changed_when: false - failed_when: false - register: discovered_nopasswd_sudoers + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.6 - - name: "5.2.4 | PATCH | Ensure users must provide password for escalation | Remove nopasswd for accounts not excluded" - when: discovered_nopasswd_sudoers.stdout | length > 0 - ansible.builtin.replace: - path: "{{ item }}" - regexp: '^((?!#|{% for name in rhel9cis_sudoers_exclude_nopasswd_list %}{{ name }}{% if not loop.last -%}|{%- endif -%}{% endfor %}).*)NOPASSWD(.*)' - replace: '\1PASSWD\2' - validate: '/usr/sbin/visudo -cf %s' - loop: "{{ discovered_nopasswd_sudoers.stdout_lines }}" - -- name: "5.2.5 | PATCH | Ensure re-authentication for privilege escalation is not disabled globally" - when: rhel9cis_rule_5_2_5 +- name: "5.2.7 | PATCH | Ensure SSH root login is disabled" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^#PermitRootLogin|^PermitRootLogin" + line: 'PermitRootLogin no' + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_7 tags: - - level1-server - - level1-workstation - - patch - - sudo - - rule_5.2.5 - - NIST800-53R5_AC-6 - block: - - name: "5.2.5 | AUDIT | Ensure re-authentication for privilege escalation is not disabled globally" - ansible.builtin.shell: grep -Ei '(!authenticate)' /etc/sudoers /etc/sudoers.d/* | cut -d':' -f1 - become: true - changed_when: false - failed_when: false - register: discovered_priv_reauth + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.7 - - name: "5.2.5 | PATCH | Ensure re-authentication for privilege escalation is not disabled globally" - when: discovered_priv_reauth.stdout | length > 0 - ansible.builtin.replace: - path: "{{ item }}" - regexp: '^([^#].*)!authenticate(.*)' - replace: '\1authenticate\2' - validate: '/usr/sbin/visudo -cf %s' - loop: "{{ discovered_priv_reauth.stdout_lines }}" - -- name: "5.2.6 | PATCH | Ensure sudo authentication timeout is configured correctly" - when: rhel9cis_rule_5_2_6 +- name: "5.2.8 | PATCH | Ensure SSH HostbasedAuthentication is disabled" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^#HostbasedAuthentication|^HostbasedAuthentication" + line: 'HostbasedAuthentication no' + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_8 tags: - - level1-server - - level1-workstation - - patch - - sudo - - rule_5.2.6 - block: - - name: "5.2.6 | AUDIT | Ensure sudo authentication timeout is configured correctly | Get files with timeout set" - ansible.builtin.shell: grep -is 'timestamp_timeout' /etc/sudoers /etc/sudoers.d/* | cut -d":" -f1 | uniq | sort - changed_when: false - failed_when: false - register: discovered_sudo_timeout_files + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.8 - - name: "5.2.6 | PATCH | Ensure sudo authentication timeout is configured correctly | Set value if no results" - when: discovered_sudo_timeout_files.stdout | length == 0 - ansible.builtin.lineinfile: - path: /etc/sudoers - regexp: 'Defaults timestamp_timeout=' - line: "Defaults timestamp_timeout={{ rhel9cis_sudo_timestamp_timeout }}" - validate: '/usr/sbin/visudo -cf %s' - - - name: "5.2.6 | PATCH | Ensure sudo authentication timeout is configured correctly | Set value if has results" - when: discovered_sudo_timeout_files.stdout | length > 0 - ansible.builtin.replace: - path: "{{ item }}" - regexp: 'timestamp_timeout=(\d+)' - replace: "timestamp_timeout={{ rhel9cis_sudo_timestamp_timeout }}" - validate: '/usr/sbin/visudo -cf %s' - loop: "{{ discovered_sudo_timeout_files.stdout_lines }}" - -- name: "5.2.7 | PATCH | Ensure access to the su command is restricted" - when: rhel9cis_rule_5_2_7 +- name: "5.2.9 | PATCH | Ensure SSH PermitEmptyPasswords is disabled" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^#PermitEmptyPasswords|^PermitEmptyPasswords" + line: 'PermitEmptyPasswords no' + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_9 tags: - - level1-server - - level1-workstation - - patch - - sudo - - rule_5.2.7 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.9 + +- name: "5.2.10 | PATCH | Ensure SSH PermitUserEnvironment is disabled" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^#PermitUserEnvironment|^PermitUserEnvironment" + line: 'PermitUserEnvironment no' + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_10 + tags: + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.10 + +- name: "5.2.11 | PATCH | Ensure SSH IgnoreRhosts is enabled" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^#IgnoreRhosts|^IgnoreRhosts" + line: 'IgnoreRhosts yes' + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_11 + tags: + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.11 + +- name: "5.2.12 | PATCH | Ensure SSH X11 forwarding is disabled" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^#X11Forwarding|^X11Forwarding" + line: 'X11Forwarding no' + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_12 + tags: + - level2-server + - level1-workstation + - patch + - ssh + - rule_5.2.12 + +- name: "5.2.13 | PATCH | Ensure SSH AllowTcpForwarding is disabled" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^#AllowTcpForwarding|^AllowTcpForwarding" + line: 'AllowTcpForwarding no' + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_13 + tags: + - level2-server + - level2-workstation + - patch + - ssh + - rule_5.2.13 + +- name: "5.2.14 | PATCH | Ensure system-wide crypto policy is not over-ridden" block: - - name: "5.2.7 | PATCH | Ensure access to the su command is restricted | Ensure sugroup exists" - ansible.builtin.group: - name: "{{ rhel9cis_sugroup }}" - state: present - register: discovered_sugroup + - name: "5.2.14 | AUDIT | Ensure system-wide crypto policy is not over-ridden" + ansible.builtin.shell: grep -i '^\s*CRYPTO_POLICY=' /etc/sysconfig/sshd + changed_when: false + failed_when: ( ssh_crypto_discovery.rc not in [ 0, 1 ] ) + register: ssh_crypto_discovery - - name: "5.2.7 | PATCH | Ensure access to the su command is restricted | remove users from group" - ansible.builtin.lineinfile: - path: /etc/group - regexp: '^{{ rhel9cis_sugroup }}(:.:.*:).*$' - line: '{{ rhel9cis_sugroup }}\g<1>' - backrefs: true + - name: "5.2.14 | PATCH | Ensure system-wide crypto policy is not over-ridden" + ansible.builtin.shell: sed -ri "s/^\s*(CRYPTO_POLICY\s*=.*)$/# \1/" /etc/sysconfig/sshd + notify: Restart sshd + when: ssh_crypto_discovery.stdout | length > 0 + when: + - rhel9cis_rule_5_2_14 + tags: + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.14 - - name: "5.2.7 | PATCH | Ensure access to the su command is restricted | Setting pam_wheel to use_uid" - ansible.builtin.lineinfile: - path: /etc/pam.d/su - regexp: '^(#)?auth\s+required\s+pam_wheel\.so' - line: 'auth required pam_wheel.so use_uid group={{ rhel9cis_sugroup }}' +- name: "5.2.15 | PATCH | Ensure SSH warning banner is configured" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: '^Banner' + line: 'Banner /etc/issue.net' + when: + - rhel9cis_rule_5_2_15 + tags: + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.15 + +- name: "5.2.16 | PATCH | Ensure SSH MaxAuthTries is set to 4 or less" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: '^(#)?MaxAuthTries \d' + line: 'MaxAuthTries 4' + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_16 + tags: + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.16 + +- name: "5.2.17 | PATCH | Ensure SSH MaxStartups is configured" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^#MaxStartups|^MaxStartups" + line: 'MaxStartups 10:30:60' + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_17 + tags: + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.17 + +- name: "5.2.18 | PATCH | Ensure SSH MaxSessions is set to 10 or less" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^#MaxSessions|^MaxSessions" + line: 'MaxSessions {{ rhel9cis_ssh_maxsessions }}' + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_18 + tags: + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.18 + +- name: "5.2.19 | PATCH | Ensure SSH LoginGraceTime is set to one minute or less" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: "^#LoginGraceTime|^LoginGraceTime" + line: "LoginGraceTime {{ rhel9cis_sshd['logingracetime'] }}" + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_19 + tags: + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.19 + +- name: "5.2.20 | PATCH | Ensure SSH Idle Timeout Interval is configured" + block: + - name: "5.2.20 | PATCH | Ensure SSH Idle Timeout Interval is configured | Add line in sshd_config for ClientAliveInterval" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: '^ClientAliveInterval' + line: "ClientAliveInterval {{ rhel9cis_sshd['clientaliveinterval'] }}" + validate: sshd -t -f %s + + - name: "5.2.20 | PATCH | Ensure SSH Idle Timeout Interval is configured | Ensure SSH ClientAliveCountMax set to <= 3" + ansible.builtin.lineinfile: + path: "{{ rhel9_cis_sshd_config_file }}" + regexp: '^ClientAliveCountMax' + line: "ClientAliveCountMax {{ rhel9cis_sshd['clientalivecountmax'] }}" + validate: sshd -t -f %s + when: + - rhel9cis_rule_5_2_20 + tags: + - level1-server + - level1-workstation + - patch + - ssh + - rule_5.2.20 diff --git a/tasks/section_5/cis_5.3.1.x.yml b/tasks/section_5/cis_5.3.1.x.yml deleted file mode 100644 index ce5ae8a..0000000 --- a/tasks/section_5/cis_5.3.1.x.yml +++ /dev/null @@ -1,55 +0,0 @@ ---- - -- name: "5.3.1.1 | PATCH | Ensure latest version of pam is installed" - when: - - rhel9cis_rule_5_3_1_1 - - ansible_facts.packages['pam'][0]['version'] is version('1.5.1-19', '<') or - "'pam' not in ansible_facts.packages" - tags: - - level1-server - - level1-workstation - - patch - - pam - - rule_5.3.1.1 - ansible.builtin.package: - name: pam - state: latest - -- name: "5.3.1.2 | PATCH | Ensure latest version of authselect is installed" - when: - - rhel9cis_rule_5_3_1_2 - - rhel9cis_authselect_pkg_update - - ansible_facts.packages['authselect'][0]['version'] is version('1.2.6-2', '<') or - "'authselect' not in ansible_facts.packages" - tags: - - level1-server - - level1-workstation - - patch - - pam - - rule_5.3.1.2 - block: - - name: "5.3.1.2 | PATCH | Ensure latest version of authselect is installed | Patch" - ansible.builtin.package: - name: authselect - state: latest - register: discovered_authselect_updated - - - name: "5.3.1.2 | AUDIT | Ensure latest version of authselect is installed | Patch" - when: discovered_authselect_updated.changed # noqa no-handler - ansible.builtin.set_fact: - authselect_update: OK - -- name: "5.3.1.3 | PATCH | Ensure libpwquality is installed" - when: - - rhel9cis_rule_5_3_1_3 - - ansible_facts.packages['libpwquality'][0]['version'] is version('1.4.4-8', '<') or - "'libpwquality' not in ansible_facts.packages" - tags: - - level1-server - - level1-workstation - - patch - - pam - - rule_5.3.1.3 - ansible.builtin.package: - name: libpwquality - state: latest diff --git a/tasks/section_5/cis_5.3.2.x.yml b/tasks/section_5/cis_5.3.2.x.yml deleted file mode 100644 index 6e1919c..0000000 --- a/tasks/section_5/cis_5.3.2.x.yml +++ /dev/null @@ -1,223 +0,0 @@ ---- - -- name: "5.3.2.1 | PATCH | Ensure active authselect profile includes pam modules" - when: - - rhel9cis_rule_5_3_2_1 - - rhel9cis_disruption_high - - rhel9cis_allow_authselect_updates - tags: - - level1-server - - level1-workstation - - manual - - patch - - authselect - - rule_5.3.2.1 - block: - - name: "5.3.2.1 | PATCH | Ensure active authselect profile includes pam modules | Create custom profiles" - when: rhel9cis_authselect_custom_profile_name not in prelim_authselect_current_profile.stdout - ansible.builtin.command: "/usr/bin/authselect create-profile {{ rhel9cis_authselect_custom_profile_name }} -b {{ rhel9cis_authselect_default_profile_to_copy }}" - changed_when: false - args: - creates: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}" - - - name: "5.3.2.1 | AUDIT | Ensure active authselect profile includes pam modules | get profile features" - ansible.builtin.command: "/usr/bin/authselect list-features custom/{{ rhel9cis_authselect_custom_profile_name }}" - changed_when: false - register: discovered_authselect_profile_features - - - name: "5.3.2.1 | PATCH | Ensure active authselect profile includes pam modules | Add missing pam modules to config | pwquality" - when: "'with-pwquality' not in discovered_authselect_profile_features.stdout_lines" - ansible.builtin.lineinfile: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^password\s*requisite\s*pam_pwquality.so.* - line: password requisite pam_pwquality.so local_users_only {include if "with-pwquality"} - loop: - - system - - password - - - name: "5.3.2.1 | PATCH | Ensure active authselect profile includes pam modules | Backup and Add pam modules" - ansible.builtin.command: "/usr/bin/authselect select custom/{{ rhel9cis_authselect_custom_profile_name }}{% if rhel9cis_rule_5_3_2_2 %} with-faillock{% endif %}{% if rhel9cis_rule_5_3_2_3 %} with-pwquality{% endif %}{% if rhel9cis_rule_5_3_2_4 %} with-pwhistory{% endif %}{% if rhel9cis_rule_5_3_3_4_1 %} without-nullok{% endif %} --force --backup=rhel9cis-preremediate-{{ lookup('pipe', 'date +%Y-%m-%d-%H%M') }}" - changed_when: true - -- name: "5.3.2.2 | PATCH | Ensure pam_faillock module is enabled" - when: - - rhel9cis_rule_5_3_2_2 - - rhel9cis_disruption_high - tags: - - level1-server - - level1-workstation - - automated - - patch - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - - authselect - - rule_5.3.2.2 - block: - - name: "5.3.2.2 | AUDIT | Ensure pam_faillock module is enabled | Get current config authselect" - block: - - name: "5.3.2.2 | AUDIT | Ensure pam_faillock module is enabled | Get current config authselect" - when: rhel9cis_allow_authselect_updates - ansible.builtin.shell: authselect current | grep faillock - changed_when: false - failed_when: discovered_authselect_current_faillock.rc not in [ 0, 1 ] - register: discovered_authselect_current_faillock - - - name: "5.3.2.2 | PATCH | Ensure pam_faillock module is enabled | Add feature if missing authselect" # noqa syntax-check[specific]" - when: - - rhel9cis_allow_authselect_updates - - discovered_authselect_current_faillock.rc != 0 - ansible.builtin.command: "/usr/bin/authselect select custom/{{ rhel9cis_authselect_custom_profile_name }}{% if rhel9cis_rule_5_3_2_2 %} with-faillock{% endif %}{% if rhel9cis_rule_5_3_2_3 %} with-pwquality{% endif %}{% if rhel9cis_rule_5_3_2_4 %} with-pwhistory{% endif %}{% if rhel9cis_rule_5_3_3_4_1 %} without-nullok{% endif %}" - changed_when: true - notify: Authselect update - - - name: "5.3.2.2 | PATCH | Ensure pam_faillock module is enabled | Get current config not authselect" - block: - - name: "5.3.2.2 | AUDIT | Ensure pam_faillock module is enabled | not authselect" - when: not rhel9cis_allow_authselect_updates - ansible.builtin.command: grep -E "(auth|account)\s*required\s*pam_faillock.so" /etc/pam.d/{system,password}-auth - changed_when: false - failed_when: false - register: discovered_faillock_not_authselect - - - name: "5.3.2.2 | PATCH | Ensure pam_faillock module is enabled | Add lines system-auth" - when: not rhel9cis_allow_authselect_updates - ansible.builtin.lineinfile: - path: "/etc/pam.d/system-auth" - regexp: "{{ item.regexp }}" - insertbefore: "{{ item.before | default(omit) }}" - insertafter: "{{ item.after | default(omit) }}" - line: "{{ item.line }}" - loop: - - regexp: "auth\\s+required\\s+pam_faillock.so\\s+preauth" - after: "auth\\s+required\\s+pam_env.so" # yamllint disable-line rule:colons - line: "auth required pam_faillock.so preauth silent deny=3 unlock_timeout={{ rhel9cis_pam_faillock_unlock_time }}" # yamllint disable-line rule:colons - - regexp: "auth\\s+required\\s+pam_faillock.so\\s+authfail" - before: "auth\\s+required\\s+pam_deny.so" - line: "auth required pam_faillock.so authfail silent deny=3 unlock_timeout={{ rhel9cis_pam_faillock_unlock_time }}" # yamllint disable-line rule:colons - - regexp: "account\\s+required\\s+pam_faillock.so" - before: "account\\s+required\\s+pam_unix.so" - line: "account required pam_faillock.so" # yamllint disable-line rule:colons - - - name: "5.3.2.2 | AUDIT | Ensure pam_faillock module is enabled | Add lines password-auth" - when: not rhel9cis_allow_authselect_updates - ansible.builtin.lineinfile: - path: "/etc/pam.d/password-auth" - regexp: "{{ item.regexp }}" - insertbefore: "{{ item.before | default(omit) }}" - insertafter: "{{ item.after | default(omit) }}" - line: "{{ item.line }}" - loop: - - regexp: "auth\\s+required\\s+pam_faillock.so\\s+preauth" - after: "auth\\s+required\\s+pam_env.so" # yamllint disable-line rule:colons - line: "auth required pam_faillock.so preauth silent deny=3 unlock_timeout={{ rhel9cis_pam_faillock_unlock_time }}" # yamllint disable-line rule:colons - - regexp: "auth\\s+required\\s+pam_faillock.so\\s+authfail" - before: "auth\\s+required\\s+pam_deny.so" - line: "auth required pam_faillock.so authfail silent deny=3 unlock_timeout={{ rhel9cis_pam_faillock_unlock_time }}" # yamllint disable-line rule:colons - - regexp: "account\\s+required\\s+pam_faillock.so" - before: "account\\s+required\\s+pam_unix.so" - line: "account required pam_faillock.so" # yamllint disable-line rule:colons - -- name: "5.3.2.3 | PATCH | Ensure pam_pwquality module is enabled" - when: - - rhel9cis_rule_5_3_2_3 - - rhel9cis_disruption_high - - rhel9cis_allow_authselect_updates - tags: - - level1-server - - level1-workstation - - automated - - patch - - NIST800-53R5_IA-5 - - authselect - - rule_5.3.2.3 - block: - - name: "5.3.2.3 | AUDIT | Ensure pam_pwquality module is enabled | Get current config" - ansible.builtin.shell: | - authselect current | grep quality - changed_when: false - failed_when: discovered_authselect_current_quality.rc not in [ 0, 1 ] - register: discovered_authselect_current_quality - - - name: "5.3.2.3 | PATCH | Ensure pam_pwquality module is enabled | Add feature if missing" - when: discovered_authselect_current_quality.rc != 0 - ansible.builtin.command: "/usr/bin/authselect select custom/{{ rhel9cis_authselect_custom_profile_name }}{% if rhel9cis_rule_5_3_2_2 %} with-faillock{% endif %}{% if rhel9cis_rule_5_3_2_3 %} with-pwquality{% endif %}{% if rhel9cis_rule_5_3_2_4 %} with-pwhistory{% endif %}{% if rhel9cis_rule_5_3_3_4_1 %} without-nullok{% endif %}" - changed_when: true - notify: Authselect update - -- name: "5.3.2.4 | PATCH | Ensure pam_pwhistory module is enabled" - when: - - rhel9cis_rule_5_3_2_4 - - rhel9cis_disruption_high - - rhel9cis_allow_authselect_updates - tags: - - level1-server - - level1-workstation - - automated - - patch - - NIST800-53R5_IA-5 - - authselect - - rule_5.3.2.4 - block: - - name: "5.3.2.4 | AUDIT | Ensure pam_pwhistory module is enabled | Get current config" - ansible.builtin.shell: | - authselect current | grep pwhistory - changed_when: false - failed_when: discovered_authselect_current_history.rc not in [ 0, 1 ] - register: discovered_authselect_current_history - - - name: "5.3.2.4 | PATCH | Ensure pam_pwhistory module is enabled | enable feature" - when: discovered_authselect_current_history.rc != 0 - ansible.builtin.command: "/usr/bin/authselect select custom/{{ rhel9cis_authselect_custom_profile_name }}{% if rhel9cis_rule_5_3_2_2 %} with-faillock{% endif %}{% if rhel9cis_rule_5_3_2_3 %} with-pwquality{% endif %}{% if rhel9cis_rule_5_3_2_4 %} with-pwhistory{% endif %}{% if rhel9cis_rule_5_3_3_4_1 %} without-nullok{% endif %}" - changed_when: true - notify: Authselect update - -- name: "5.3.2.5 | PATCH | Ensure pam_unix module is enabled" - when: - - rhel9cis_rule_5_3_2_5 - - rhel9cis_disruption_high - - rhel9cis_allow_authselect_updates - tags: - - level1-server - - level1-workstation - - automated - - patch - - NIST800-53R5_IA-5 - - authselect - - rule_5.3.2.5 - block: - - name: "5.3.2.5 | AUDIT | Ensure pam_unix module is enabled" - ansible.builtin.shell: grep -P -- '\b(pam_unix\.so)\b' /etc/authselect/"$(head -1 /etc/authselect/authselect.conf)"/{system,password}-auth - changed_when: false - failed_when: discovered_authselect_pam_unix.rc not in [ 0, 1 ] - register: discovered_authselect_pam_unix - - - name: "5.3.2.5 | PATCH | Ensure pam_unix module is enabled | system-auth" - when: "'system-auth:password' not in discovered_authselect_pam_unix.stdout" - ansible.builtin.lineinfile: - path: /etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/system-auth - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - backrefs: true - insertafter: "{{ item.after | default(omit) }}" - insertbefore: "{{ item.before | default(omit) }}" - loop: - - { regexp: '^(auth\s+)sufficient(\s+pam_unix.so.*)(.*)', line: '\1sufficient\2\3', after: '^auth.*pam_faillock.*preauth' } - - { regexp: '^(password\s+)sufficient(\s+pam_unix.so.*)(.*)', line: '\1sufficient\2\3', before: '^password.*pam_deny.so' } - notify: Authselect update - - - name: "5.3.2.5 | PATCH | Ensure pam_unix module is enabled | password-auth" - when: "'password-auth:password' not in discovered_authselect_pam_unix.stdout" - ansible.builtin.lineinfile: - path: /etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/password-auth - line: "{{ item.line }}" - regexp: "{{ item.regexp }}" - backrefs: true - insertafter: "{{ item.after | default(omit) }}" - insertbefore: "{{ item.before | default(omit) }}" - loop: - - { regexp: '^(auth\s+)sufficient(\s+pam_unix.so.*)(.*)', line: '\1sufficient\2\2', after: '^auth.*pam_faillock.*preauth' } - - { regexp: '^(password\s+)sufficient(\s+pam_unix.so.*)(.*)', line: '\1sufficient\2\3', before: '^password.*pam_deny.so' } - notify: Authselect update diff --git a/tasks/section_5/cis_5.3.3.1.x.yml b/tasks/section_5/cis_5.3.3.1.x.yml deleted file mode 100644 index 0aadbe3..0000000 --- a/tasks/section_5/cis_5.3.3.1.x.yml +++ /dev/null @@ -1,128 +0,0 @@ ---- - -- name: "5.3.3.1.1 | PATCH | Ensure password failed attempts lockout is configured" - when: rhel9cis_rule_5_3_3_1_1 - tags: - - level1-server - - level1-workstation - - automated - - patch - - pam - - rule_5.3.3.1.1 - block: - - name: "5.3.3.1.1 | PATCH | Ensure password failed attempts lockout is configured | faillock.conf" - ansible.builtin.lineinfile: - path: /etc/security/faillock.conf - state: present - regexp: '^(#|)\s*deny\s*=\s*\d' - line: "deny = {{ rhel9cis_pam_faillock_deny }}" - - - name: "5.3.3.1.1 | PATCH | Ensure password failed attempts lockout is configured | remove deny from pam files NOT AuthSelect" - when: - - not rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/pam.d/{{ item }}-auth" - regexp: ^(\s*auth\s+(?:requisite|required|sufficient)\s+pam_faillock\.so)(.*)\s+deny\s*=\s*\S+(.*$) - replace: \1 \2\3 - loop: - - password - - system - - - name: "5.3.3.1.1 | PATCH | Ensure password failed attempts lockout is configured | remove deny from AuthSelect config" - when: - - rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*auth\s+(requisite|required|sufficient)\s+pam_faillock\.so)(.*)\s+deny\s*=\s*\S+(.*$) - replace: \1\2\3 - loop: - - password - - system - notify: Authselect update - -- name: "5.3.3.1.2 | PATCH | Ensure password unlock time is configured" - when: rhel9cis_rule_5_3_3_1_2 - tags: - - level1-server - - level1-workstation - - automated - - patch - - pam - - rule_5.3.3.1.2 - block: - - name: "5.3.3.1.2 | PATCH | Ensure password unlock time is configured | faillock.conf" - ansible.builtin.lineinfile: - path: /etc/security/faillock.conf - state: present - regexp: '^(#|)\s*unlock_time\s*=\s*\d' - line: "unlock_time = {{ rhel9cis_pam_faillock_unlock_time }}" - - - name: "5.3.3.1.2 | PATCH | Ensure password unlock time is configured | remove unlock from pam files NOT AuthSelect" - when: - - rhel9cis_disruption_high - - not rhel9cis_allow_authselect_updates - ansible.builtin.replace: - path: "/etc/pam.d/{{ item }}-auth" - regexp: ^(\s*auth\s+(requisite|required|sufficient)\s+pam_faillock\.so)(.*)\s+unlock_time\s*=\s*\S+(.*$) - replace: \1\2\3 - loop: - - password - - system - - - name: "5.3.3.1.2 | PATCH | Ensure password unlock time is configured | remove unlock from pam files AuthSelect" - when: - - rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*auth\s+(requisite|required|sufficient)\s+pam_faillock\.so)(.*)\s+unlock_time\s*=\s*\S+(.*$) - replace: \1\2\3 - loop: - - password - - system - notify: Authselect update - -- name: "5.3.3.1.3 | PATCH | Ensure password failed attempts lockout includes root account" - when: rhel9cis_rule_5_3_3_1_3 - tags: - - level1-server - - level1-workstation - - automated - - patch - - pam - - rule_5.3.3.1.3 - block: - - name: "5.3.3.1.3 | PATCH | Ensure password failed attempts lockout includes root account | configure faillock.conf" - ansible.builtin.lineinfile: - path: /etc/security/faillock.conf - regexp: '^{{ rhel9cis_pamroot_lock_option }}' - line: "{{ rhel9cis_pamroot_lock_option }}" - insertafter: '^# end of pam-auth-update config' - create: true - mode: 'u-x,go-wx' - - - name: "5.3.3.1.3 | PATCH | Ensure password failed attempts lockout includes root account | remove lockout from pam files NOT AuthSelect" - when: - - rhel9cis_disruption_high - - not rhel9cis_allow_authselect_updates - ansible.builtin.replace: - path: "/etc/pam.d/{{ item }}-auth" - regexp: ^(\s*auth\s+(requisite|required|sufficient)\s+pam_faillock\.so)(.*)\s(even_deny_root|root_unlock_time=\d*)"(\s*=\s*\d|.*)\S+(.*$) - replace: \1\2\4 - loop: - - password - - system - - - name: "5.3.3.1.3 | PATCH | Ensure password failed attempts lockout includes root account | remove lockout from pam files AuthSelect" - when: - - rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*auth\s+(requisite|required|sufficient)\s+pam_faillock\.so)(.*)\s(even_deny_root|root_unlock_time=\d*)"(\s*=\s*\d|.*)\S+(.*$) - replace: \1\2\4 - loop: - - password - - system diff --git a/tasks/section_5/cis_5.3.3.2.x.yml b/tasks/section_5/cis_5.3.3.2.x.yml deleted file mode 100644 index e8e1530..0000000 --- a/tasks/section_5/cis_5.3.3.2.x.yml +++ /dev/null @@ -1,357 +0,0 @@ ---- - -- name: "5.3.3.2.1 | PATCH | Ensure password number of changed characters is configured" - when: rhel9cis_rule_5_3_3_2_1 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.3.3.2.1 - - NIST800-53R5_IA-5 - - pam - block: - - name: "5.3.3.2.1 | PATCH | Ensure password number of changed characters is configured | Remove difok from conf files except expected file" - when: - - item != rhel9cis_passwd_difok_file - - rhel9cis_disruption_high - ansible.builtin.lineinfile: - path: "{{ item }}" - regexp: 'difok\s*=\s*\d+\b' - state: absent - loop: - - /etc/security/pwquality.conf - - /etc/pam.d/system-auth - - /etc/pam.d/password-auth - - "{{ prelim_pam_pwquality_confs.files | default([]) }}" - - - name: "5.3.3.2.1 | PATCH | Ensure password number of changed characters is configured | Ensure difok file exists" - ansible.builtin.template: - src: "{{ rhel9cis_passwd_difok_file }}.j2" - dest: "/{{ rhel9cis_passwd_difok_file }}" - owner: root - group: root - mode: 'go-rwx' - - - name: "5.3.3.2.1 | PATCH | Ensure password number of changed characters is configured | Remove difok from pam files Not AuthSelect" - when: - - not rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/pam.d/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwquality\.so)(.*)\sdifok=\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - - - name: "5.3.3.2.1 | PATCH | Ensure password number of changed characters is configured | Remove difok from pam files AuthSelect" - when: - - rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwquality\.so)(.*)\sdifok=\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - notify: Authselect update - -- name: "5.3.3.2.2 | PATCH | Ensure password length is configured" - when: rhel9cis_rule_5_3_3_2_2 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.3.3.2.2 - - NIST800-53R5_IA-5 - - pam - block: - - name: "5.3.3.2.2 | PATCH | Ensure minimum password length is configured | Remove minlen from conf files except expected file" - when: - - item != rhel9cis_passwd_minlen_file - - rhel9cis_disruption_high - ansible.builtin.lineinfile: - path: "{{ item }}" - regexp: 'minlen\s*=\s*\d+\b' - state: absent - loop: - - /etc/security/pwquality.conf - - /etc/pam.d/system-auth - - /etc/pam.d/password-auth - - "{{ prelim_pam_pwquality_confs.files | default([]) }}" - - - name: "5.3.3.2.2 | PATCH | Ensure minimum password length is configured | Ensure minlen file exists" - ansible.builtin.template: - src: "{{ rhel9cis_passwd_minlen_file }}.j2" - dest: "/{{ rhel9cis_passwd_minlen_file }}" - owner: root - group: root - mode: 'go-rwx' - - - name: "5.3.3.2.2 | PATCH | Ensure minimum password length is configured | Remove minlen from pam files NOT AuthSelect" - when: - - not rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/pam.d/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwquality\.so)(.*)\sminlen=\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - - - name: "5.3.3.2.2 | PATCH | Ensure minimum password length is configured | Remove minlen from pam files AuthSelect" - when: - - rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwquality\.so)(.*)\sminlen=\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - notify: Authselect update - -- name: "5.3.3.2.3 | PATCH | Ensure password complexity is configured" - when: rhel9cis_rule_5_3_3_2_3 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.3.3.2.3 - - NIST800-53R5_IA-5 - - pam - block: - - name: "5.3.3.2.3 | PATCH | Ensure password complexity is configured | Remove pwd complex settings from conf files except expected file" - when: - - item != rhel9cis_passwd_complex_file - - rhel9cis_disruption_high - ansible.builtin.lineinfile: - path: "{{ item }}" - regexp: '(minclass|[dulo]credit)\s*=\s*(-\d|\d+)\b' - state: absent - loop: - - /etc/security/pwquality.conf - - /etc/pam.d/system-auth - - /etc/pam.d/password-auth - - "{{ prelim_pam_pwquality_confs.files | default([]) }}" - - - name: "5.3.3.2.3 | PATCH | Ensure password complexity is configured | Ensure complexity file exists" - ansible.builtin.template: - src: "{{ rhel9cis_passwd_complex_file }}.j2" - dest: "/{{ rhel9cis_passwd_complex_file }}" - owner: root - group: root - mode: 'go-rwx' - - - name: "5.3.3.2.3 | PATCH | Ensure password complexity is configured | Remove complexity from pam files NOT AuthSelect" - when: - - not rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/pam.d/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwquality\.so)(.*)\s(minclass=[0-3]|[dulo]credit=[^-]\d*)(.*$) - replace: \1\2\4 - loop: - - password - - system - - - name: "5.3.3.2.3 | PATCH | Ensure password complexity is configured | Remove complexity from pam files AuthSelect" - when: - - rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwquality\.so)(.*)\s(minclass=[0-3]|[dulo]credit=[^-]\d*)(.*$) - replace: \1\2\4 - loop: - - password - - system - notify: Authselect update - -- name: "5.3.3.2.4 | PATCH | Ensure password same consecutive characters is configured" - when: rhel9cis_rule_5_3_3_2_4 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.3.3.2.4 - - NIST800-53R5_IA-5 - - pam - block: - - name: "5.3.3.2.4 | PATCH | Ensure password same consecutive characters is configured | Remove maxrepeat settings from conf files except expected file" - when: item != rhel9cis_passwd_maxrepeat_file - ansible.builtin.lineinfile: - path: "{{ item }}" - regexp: 'maxrepeat\s*=\s*\d+\b' - state: absent - loop: - - /etc/security/pwquality.conf - - /etc/pam.d/system-auth - - /etc/pam.d/password-auth - - "{{ prelim_pam_pwquality_confs.files | default([]) }}" - - - name: "5.3.3.2.4 | PATCH | Ensure password same consecutive characters is configured | Ensure maxrepeat file exists" - ansible.builtin.template: - src: "{{ rhel9cis_passwd_maxrepeat_file }}.j2" - dest: "/{{ rhel9cis_passwd_maxrepeat_file }}" - owner: root - group: root - mode: 'go-rwx' - - - name: "5.3.3.2.4 | PATCH | Ensure password same consecutive characters is configured | Remove maxrepeat from pam files NOT AuthSelect" - when: - - not rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/pam.d/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwquality\.so)(.*)\smaxrepeat\s*=\s*\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - - - name: "5.3.3.2.4 | PATCH | Ensure password same consecutive characters is configured | Remove maxrepeat from pam files AuthSelect" - when: - - rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwquality\.so)(.*)\smaxrepeat\s*=\s*\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - notify: Authselect update - -- name: "5.3.3.2.5 | PATCH | Ensure password maximum sequential characters is is configured" - when: rhel9cis_rule_5_3_3_2_5 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.3.3.2.5 - - NIST800-53R5_IA-5 - - pam - block: - - name: "5.3.3.2.5 | PATCH | Ensure password maximum sequential characters is configured | Remove maxsequence settings from conf files except expected file" - when: - - item != rhel9cis_passwd_maxsequence_file - - rhel9cis_disruption_high - ansible.builtin.lineinfile: - path: "{{ item }}" - regexp: 'maxsequence\s*=\s*\d+\b' - state: absent - loop: - - /etc/security/pwquality.conf - - /etc/pam.d/system-auth - - /etc/pam.d/password-auth - - "{{ prelim_pam_pwquality_confs.files | default([]) }}" - - - name: "5.3.3.2.5 | PATCH | Ensure password maximum sequential characters is configured | Ensure maxsequence file exists" - ansible.builtin.template: - src: "{{ rhel9cis_passwd_maxsequence_file }}.j2" - dest: "/{{ rhel9cis_passwd_maxsequence_file }}" - owner: root - group: root - mode: 'go-rwx' - - - name: "5.3.3.2.5 | PATCH | Ensure password maximum sequential characters is configured | Remove maxsequence from pam files NOT AuthSelect" - when: - - not rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/pam.d/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwquality\.so)(.*)\smaxsequence\s*=\s*\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - - - name: "5.3.3.2.5 | PATCH | Ensure password maximum sequential characters is configured | Remove maxsequence from pam files AuthSelect" - when: - - rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwquality\.so)(.*)\smaxsequence\s*=\s*\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - notify: Authselect update - -- name: "5.3.3.2.6 | PATCH | Ensure password dictionary check is enabled" - when: rhel9cis_rule_5_3_3_2_6 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.3.3.2.6 - - NIST800-53R5_IA-5 - - pam - block: - - name: "5.3.3.2.6 | PATCH | Ensure password dictionary check is enabled | Remove dictcheck settings from conf files except expected file" - when: - - item != rhel9cis_passwd_dictcheck_file - ansible.builtin.lineinfile: - path: "{{ item }}" - regexp: 'dictcheck\s*=\s*\d+\b' - state: absent - loop: - - /etc/security/pwquality.conf - - /etc/pam.d/system-auth - - /etc/pam.d/password-auth - - "{{ prelim_pam_pwquality_confs.files | default([]) }}" - - - name: "5.3.3.2.6 | PATCH | Ensure password dictionary check is enabled | Ensure dictcheck file exists" - ansible.builtin.template: - src: "{{ rhel9cis_passwd_dictcheck_file }}.j2" - dest: "/{{ rhel9cis_passwd_dictcheck_file }}" - owner: root - group: root - mode: 'go-rwx' - - - name: "5.3.3.2.6 | PATCH | Ensure password dictionary check is enabled | Remove dictcheck from pam files NOT AuthSelect" - when: - - not rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/pam.d/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwquality\.so)(.*)\sdictcheck\s*=\s*\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - notify: Authselect update - - - name: "5.3.3.2.6 | PATCH | Ensure password dictionary check is enabled | Remove dictcheck from pam files AuthSelect" - when: - - rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwquality\.so)(.*)\sdictcheck\s*=\s*\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - notify: Authselect update - -- name: "5.3.3.2.7 | PATCH | Ensure password quality is enforced for the root user" - when: rhel9cis_rule_5_3_3_2_7 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.3.3.2.7 - - NIST800-53R5_IA-5 - - pam - ansible.builtin.template: - src: "{{ rhel9cis_passwd_quality_enforce_root_file }}.j2" - dest: "/{{ rhel9cis_passwd_quality_enforce_root_file }}" - owner: root - group: root - mode: 'o-rwx' diff --git a/tasks/section_5/cis_5.3.3.3.x.yml b/tasks/section_5/cis_5.3.3.3.x.yml deleted file mode 100644 index 9daf71a..0000000 --- a/tasks/section_5/cis_5.3.3.3.x.yml +++ /dev/null @@ -1,104 +0,0 @@ ---- - -- name: "5.3.3.3.1 | PATCH | Ensure password history remember is configured" - when: rhel9cis_rule_5_3_3_3_1 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.3.3.3.1 - - pam - block: - - name: "5.3.3.3.1 | AUDIT | Ensure password history remember is configured | Check existing files" - ansible.builtin.shell: grep -Psi -- '^\h*password\s+[^#\n\r]+\h+pam_pwhistory\.so\s+([^#\n\r]+\s+)?remember=\d+\b' /etc/pam.d/password-auth /etc/pam.d/system-auth - changed_when: false - failed_when: discovered_pwhistory_remember.rc not in [0, 1] - register: discovered_pwhistory_remember - - - name: "5.3.3.3.1 | PATCH | Ensure password number of changed characters is configured | Ensure remember is set pwhistory file" - ansible.builtin.lineinfile: - path: "/etc/security/pwhistory.conf" - regexp: remember\s*=\s*\d* - line: remember = {{ rhel9cis_pamd_pwhistory_remember }} - - - name: "5.3.3.3.1 | PATCH | Ensure password number of changed characters is configured | Remove remember from pam files NOT AuthSelect" - when: - - not rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/pam.d/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwhistory\.so)(.*)\sremember=\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - - - name: "5.3.3.3.1 | PATCH | Ensure password number of changed characters is configured | Remove remember from pam files AuthSelect" - when: - - rhel9cis_allow_authselect_updates - - rhel9cis_disruption_high - ansible.builtin.replace: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwhistory\.so)(.*)\sremember=\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - notify: Authselect update - -- name: "5.3.3.3.2 | PATCH | Ensure password history is enforced for the root user" - when: rhel9cis_rule_5_3_3_3_2 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.3.3.3.2 - - pam - ansible.builtin.lineinfile: - path: "/etc/security/pwhistory.conf" - regexp: ^\s*(?#)enforce_for_root - line: enforce_for_root - -- name: "5.3.3.3.3 | PATCH | Ensure pam_pwhistory includes use_authtok" - when: rhel9cis_rule_5_3_3_3_3 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.3.3.3.3 - - pam - block: - - name: "5.3.3.3.3 | AUDIT | Ensure pam_pwhistory includes use_authtok | Check existing files" - ansible.builtin.shell: grep -Psic -- '^\h*password\h+[^#\n\r]+\h+pam_pwhistory\.so\h+([^#\n\r]+\h+)?use_authtok\b' /etc/pam.d/{system,password}-auth - register: discovered_pwhistory_use_authtok - changed_when: false - failed_when: discovered_pwhistory_use_authtok.rc not in [0, 1] - - - name: "5.3.3.3.3 | PATCH | Ensure pam_pwhistory includes use_authtok | Ensure use_authtok is set" - when: - - not rhel9cis_allow_authselect_updates - - discovered_pwhistory_use_authtok.stdout | length == 0 - - rhel9cis_disruption_high - ansible.builtin.lineinfile: - path: "{{ item }}" - regexp: ^password\s*pam_pwhistory\.so\s*.*\s(!?use_authtok) - line: password required pam_pwhistory.so use_authtok - insertbefore: ^password.*pam_deny.so - loop: - - /etc/pam.d/password-auth - - /etc/pam.d/system-auth - - - name: "PATCH | Ensure pam_pwhistory includes use_authtok | add authtok to pam files AuthSelect" - when: - - rhel9cis_allow_authselect_updates - - discovered_pwhistory_use_authtok.stdout | length == 0 - - rhel9cis_disruption_high - ansible.builtin.lineinfile: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_pwhistory\.so)(.*)\suse_authtok(.*$) - line: \1\2 use_authtok\3 - backrefs: true - loop: - - password - - system - notify: Authselect update diff --git a/tasks/section_5/cis_5.3.3.4.x.yml b/tasks/section_5/cis_5.3.3.4.x.yml deleted file mode 100644 index ddca97a..0000000 --- a/tasks/section_5/cis_5.3.3.4.x.yml +++ /dev/null @@ -1,159 +0,0 @@ ---- - -- name: "5.3.3.4.1 | PATCH | Ensure pam_unix does not include nullok" - when: - - rhel9cis_rule_5_3_3_4_1 - - rhel9cis_disruption_high - tags: - - level1-server - - level1-workstation - - patch - - rule_5.3.3.4.1 - - pam - block: - - name: "5.3.3.4.1 | PATCH | Ensure pam_unix does not include nullok | capture state" - ansible.builtin.shell: grep -E "pam_unix.so.*nullok" /etc/pam.d/*-auth | cut -d ':' -f1 | uniq - changed_when: false - failed_when: discovered_pam_nullok.rc not in [ 0, 1 ] - register: discovered_pam_nullok - - - name: "5.3.3.4.1 | PATCH | Ensure pam_unix does not include nullok | Ensure nullok removed" - when: - - discovered_pam_nullok.stdout | length > 0 - - not rhel9cis_allow_authselect_updates - ansible.builtin.replace: - path: "{{ item }}" - regexp: nullok - replace: '' - loop: "{{ discovered_pam_nullok.stdout_lines }}" - - - name: "5.3.3.4.1 | PATCH | Ensure password number of changed characters is configured | Remove nullok from pam files AuthSelect" - when: rhel9cis_allow_authselect_updates - ansible.builtin.replace: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_unix\.so)(.*)\snullok(.*$) - replace: \1\2\3 - loop: - - password - - system - notify: Authselect update - -- name: "5.3.3.4.2 | PATCH | Ensure pam_unix does not include remember" - when: - - rhel9cis_rule_5_3_3_4_2 - - rhel9cis_disruption_high - tags: - - level1-server - - level1-workstation - - patch - - pam - - rule_5.3.3.4.2 - block: - - name: "5.3.3.4.2 | AUDIT | Ensure pam_unix does not include remember | capture state" - ansible.builtin.shell: grep -E "password.*pam_unix.so.*remember" /etc/pam.d/*-auth | cut -d ':' -f1 | uniq - changed_when: false - failed_when: discovered_pam_remember.rc not in [ 0, 1 ] - register: discovered_pam_remember - - - name: "5.3.3.4.2 | PATCH | Ensure pam_unix does not include remember | Ensure remember removed" - when: - - not rhel9cis_allow_authselect_updates - - discovered_pam_remember.stdout | length > 0 - ansible.builtin.replace: - path: "{{ item }}" - regexp: remember - replace: '' - loop: "{{ discovered_pam_remember.stdout_lines }}" - - - name: "5.3.3.4.2 | PATCH | Ensure pam_unix does not include remember | Remove remember from pam files AuthSelect" - when: rhel9cis_allow_authselect_updates - ansible.builtin.replace: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*password\s+(requisite|required|sufficient)\s+pam_unix\.so)(.*)\sremember\s*=\s*=\d*(.*$) - replace: \1\2\3 - loop: - - password - - system - notify: Authselect update - -- name: "5.3.3.4.3 | PATCH | Ensure pam_unix includes a strong password hashing algorithm" - when: - - rhel9cis_rule_5_3_3_4_3 - - rhel9cis_disruption_high - tags: - - level1-server - - level1-workstation - - patch - - pam - - rule_5.3.3.4.3 - - NIST800-53R5_IA-5 - block: - - name: "5.3.3.4.3 | AUDIT | Ensure pam_unix includes a strong password hashing algorithm | capture state" - ansible.builtin.shell: grep -E "password.*pam_unix.so.*(sha512|yescrypt)" /etc/pam.d/*-auth | cut -d ':' -f1 | uniq - changed_when: false - failed_when: discovered_pam_pwhash.rc not in [ 0, 1 ] - register: discovered_pam_pwhash - - - name: "5.3.3.4.3 | PATCH | Ensure pam_unix includes a strong password hashing algorithm | Ensure hash algorithm set" - when: - - not rhel9cis_allow_authselect_updates - - discovered_pam_remember.stdout | length > 0 - ansible.builtin.replace: - path: "{{ item }}" - regexp: "(md5|bigcrypt|sha256|blowfish|gost_yescrypt|sha512|yescrypt)" - replace: '{{ rhel9cis_passwd_hash_algo }}' - loop: "{{ discovered_pam_remember.stdout_lines }}" - - - name: "5.3.3.4.3 | PATCH | Ensure pam_unix includes a strong password hashing algorithm | Add hash algorithm to pam files AuthSelect" - when: rhel9cis_allow_authselect_updates - ansible.builtin.lineinfile: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*password\s+)(requisite|required|sufficient)(\s+pam_unix.so\s)(.*)(sha512|yescrypt)(.*$) - line: \1\2\3\4{{ rhel9cis_passwd_hash_algo }}\6 - backrefs: true - loop: - - password - - system - notify: Authselect update - -- name: "5.3.3.4.4 | PATCH | Ensure pam_unix includes use_authtok" - when: - - rhel9cis_rule_5_3_3_4_4 - - rhel9cis_disruption_high - tags: - - level1-server - - level1-workstation - - patch - - pam - - rule_5.3.3.4.4 - - NIST800-53R5_IA-5 - block: - - name: "5.3.3.4.4 | PATCH | Ensure pam_unix includes use_authtok | capture state" - ansible.builtin.shell: grep -PH -- '^\h*^password\h*[^#\n\r]+\h+pam_unix.so\b' /etc/pam.d/{password,system}-auth | grep -Pv -- '\buse_authtok\b' - changed_when: false - failed_when: discovered_pam_authtok.rc not in [ 0, 1 ] - register: discovered_pam_authtok - - - name: "5.3.3.4.4 | PATCH | Ensure pam_unix includes use_authtok | pam_files" - when: - - not rhel9cis_allow_authselect_updates - - discovered_pam_authtok is defined - - discovered_pam_authtok.stdout | length > 0 - ansible.builtin.lineinfile: - path: "{{ item }}" - regexp: ^(\s*password\s+)(requisite|required|sufficient)(\s+pam_unix.so\s)(.*)use_authtok(.*$) - line: \1\2\3\4use_authtok \5 - backrefs: true - loop: "{{ discovered_pam_authtok.stdout_lines }}" - - - name: "5.3.3.4.4 | PATCH | Ensure pam_unix includes use_authtok | Add use_authtok pam files AuthSelect" - when: rhel9cis_allow_authselect_updates - ansible.builtin.lineinfile: - path: "/etc/authselect/custom/{{ rhel9cis_authselect_custom_profile_name }}/{{ item }}-auth" - regexp: ^(\s*password\s+)(requisite|required|sufficient)(\s+pam_unix.so\s)(.*)use_authtok(.*$) - line: \1\2\3\4use_authtok\5 - backrefs: true - loop: - - password - - system - notify: Authselect update diff --git a/tasks/section_5/cis_5.3.x.yml b/tasks/section_5/cis_5.3.x.yml new file mode 100644 index 0000000..2f63b23 --- /dev/null +++ b/tasks/section_5/cis_5.3.x.yml @@ -0,0 +1,138 @@ +--- + +- name: "5.3.1 | PATCH | Ensure sudo is installed" + ansible.builtin.package: + name: sudo + state: present + when: + - rhel9cis_rule_5_3_1 + tags: + - level1-server + - level1-workstation + - patch + - sudo + - rule_5.3.1 + +- name: "5.3.2 | PATCH | Ensure sudo commands use pty" + ansible.builtin.lineinfile: + path: /etc/sudoers + line: "Defaults use_pty" + validate: '/usr/sbin/visudo -cf %s' + when: + - rhel9cis_rule_5_3_2 + tags: + - level1-server + - level1-workstation + - patch + - sudo + - rule_5.3.2 + +- name: "5.3.3 | PATCH | Ensure sudo log file exists" + ansible.builtin.lineinfile: + path: /etc/sudoers + regexp: '^Defaults logfile=' + line: 'Defaults logfile="{{ rhel9cis_sudolog_location }}"' + validate: '/usr/sbin/visudo -cf %s' + when: + - rhel9cis_rule_5_3_3 + tags: + - level1-server + - level1-workstation + - patch + - sudo + - rule_5.3.3 + +- name: "5.3.4 | PATCH | Ensure users must provide password for escalation" + ansible.builtin.replace: + path: "{{ item }}" + regexp: '^([^#|{% if system_is_ec2 %}ec2-user{% endif %}].*)NOPASSWD(.*)' + replace: '\1PASSWD\2' + validate: '/usr/sbin/visudo -cf %s' + loop: "{{ rhel9cis_sudoers_files.stdout_lines }}" + when: + - rhel9cis_rule_5_3_4 + tags: + - level2-server + - level2-workstation + - patch + - sudo + - rule_5.3.4 + +- name: "5.3.5 | PATCH | Ensure re-authentication for privilege escalation is not disabled globally" + ansible.builtin.replace: + path: "{{ item }}" + regexp: '^([^#].*)!authenticate(.*)' + replace: '\1authenticate\2' + validate: '/usr/sbin/visudo -cf %s' + loop: "{{ rhel9cis_sudoers_files.stdout_lines }}" + when: + - rhel9cis_rule_5_3_5 + tags: + - level1-server + - level1-workstation + - patch + - sudo + - rule_5.3.5 + +- name: "5.3.6 | PATCH | Ensure sudo authentication timeout is configured correctly" + block: + - name: "5.3.6 | AUDIT | Ensure sudo authentication timeout is configured correctly | Get files with timeout set" + ansible.builtin.shell: grep -is 'timestamp_timeout' /etc/sudoers /etc/sudoers.d/* | cut -d":" -f1 | uniq | sort + changed_when: false + failed_when: false + register: rhel9cis_5_3_6_timeout_files + + - name: "5.3.6 | PATCH | Ensure sudo authentication timeout is configured correctly | Set value if no results" + ansible.builtin.lineinfile: + path: /etc/sudoers + regexp: 'Defaults timestamp_timeout=' + line: "Defaults timestamp_timeout={{ rhel9cis_sudo_timestamp_timeout }}" + validate: '/usr/sbin/visudo -cf %s' + when: rhel9cis_5_3_6_timeout_files.stdout | length == 0 + + - name: "5.3.6 | PATCH | Ensure sudo authentication timeout is configured correctly | Set value if has results" + ansible.builtin.replace: + path: "{{ item }}" + regexp: 'timestamp_timeout=(\d+)' + replace: "timestamp_timeout={{ rhel9cis_sudo_timestamp_timeout }}" + validate: '/usr/sbin/visudo -cf %s' + loop: "{{ rhel9cis_5_3_6_timeout_files.stdout_lines }}" + when: rhel9cis_5_3_6_timeout_files.stdout | length > 0 + when: + - rhel9cis_rule_5_3_6 + tags: + - level1-server + - level1-workstation + - patch + - sudo + - rule_5.3.6 + +- name: "5.3.7 | PATCH | Ensure access to the su command is restricted" + block: + + - name: "5.3.7 | PATCH | Ensure access to the su command is restricted | Ensure sugroup exists" + ansible.builtin.group: + name: "{{ rhel9cis_sugroup }}" + state: present + register: rhel9cis_5_3_7_sugroup + + - name: "5.3.7 | PATCH | Ensure access to the su command is restricted | remove users from group" + ansible.builtin.lineinfile: + path: /etc/group + regexp: '^{{ rhel9cis_sugroup }}(:.:.*:).*$' + line: '{{ rhel9cis_sugroup }}\g<1>' + backrefs: true + + - name: "5.3.7 | PATCH | Ensure access to the su command is restricted | Setting pam_wheel to use_uid" + ansible.builtin.lineinfile: + path: /etc/pam.d/su + regexp: '^(#)?auth\s+required\s+pam_wheel\.so' + line: 'auth required pam_wheel.so use_uid group={{ rhel9cis_sugroup }}' + when: + - rhel9cis_rule_5_3_7 + tags: + - level1-server + - level1-workstation + - patch + - sudo + - rule_5.3.7 diff --git a/tasks/section_5/cis_5.4.1.x.yml b/tasks/section_5/cis_5.4.1.x.yml deleted file mode 100644 index badca42..0000000 --- a/tasks/section_5/cis_5.4.1.x.yml +++ /dev/null @@ -1,193 +0,0 @@ ---- - -- name: "5.4.1.1 | PATCH | Ensure password expiration is 365 days or less" - when: rhel9cis_rule_5_4_1_1 - tags: - - level1-server - - level1-workstation - - patch - - password - - rule_5.4.1.1 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - block: - - name: "5.4.1.1 | PATCH | Ensure password expiration is 365 days or less" - ansible.builtin.lineinfile: - path: /etc/login.defs - regexp: '^PASS_MAX_DAYS' - line: "PASS_MAX_DAYS {{ rhel9cis_pass_max_days }}" - - - name: "5.4.1.1 | AUDIT | Ensure password expiration is 365 days or less | Get existing users PASS_MAX_DAYS" - ansible.builtin.shell: "awk -F: '(/^[^:]+:[^!*]/ && ($5> {{ rhel9cis_pass_max_days }} || $5< {{ rhel9cis_pass_max_days }} || $5 == -1)){print $1}' /etc/shadow" - changed_when: false - failed_when: false - check_mode: false - register: discovered_max_days - - - name: "5.4.1.1 | PATCH | Ensure password expiration is 365 days or less | Set existing users PASS_MAX_DAYS" - when: - - discovered_max_days.stdout_lines | length > 0 - - item in prelim_interactive_users | map(attribute='username') | list - - rhel9cis_force_user_maxdays - ansible.builtin.user: - name: "{{ item }}" - password_expire_max: "{{ rhel9cis_pass_max_days }}" - loop: "{{ discovered_max_days.stdout_lines }}" - -- name: "5.4.1.2 | PATCH | Ensure minimum password days is configured" - when: rhel9cis_rule_5_4_1_2 - tags: - - level1-server - - level1-workstation - - patch - - password - - rule_5.4.1.2 - block: - - name: "5.4.1.2 | PATCH | Ensure minimum password days is configured | set login.defs" - ansible.builtin.lineinfile: - path: /etc/login.defs - regexp: '^PASS_MIN_DAYS' - line: "PASS_MIN_DAYS {{ rhel9cis_pass_min_days }}" - - - name: "5.4.1.2 | AUDIT | Ensure minimum password days is configured | Get existing users PASS_MIN_DAYS" - ansible.builtin.shell: "awk -F: '/^[^:]+:[^!*]/ && $4< {{ rhel9cis_pass_min_days }} {print $1}' /etc/shadow" - changed_when: false - failed_when: false - register: discovered_min_days - - - name: "5.4.1.2 | PATCH | Ensure minimum password days is configured | Set existing users PASS_MIN_DAYS" - when: - - discovered_min_days.stdout_lines | length > 0 - - item in prelim_interactive_users | map(attribute='username') | list - - rhel9cis_force_user_mindays - ansible.builtin.user: - name: "{{ item }}" - password_expire_min: "{{ rhel9cis_pass_min_days }}" - loop: "{{ discovered_min_days.stdout_lines }}" - -- name: "5.4.1.3 | PATCH | Ensure password expiration warning days is configured" - when: rhel9cis_rule_5_4_1_3 - tags: - - level1-server - - level1-workstation - - patch - - password - - rule_5.4.1.3 - block: - - name: "5.4.1.3 | PATCH | Ensure password expiration warning days is configured | set login.defs" - ansible.builtin.lineinfile: - path: /etc/login.defs - regexp: '^PASS_WARN_AGE' - line: "PASS_WARN_AGE {{ rhel9cis_pass_warn_age }}" - - - name: "5.4.1.3 | AUDIT | Ensure password expiration warning days is configured | Get existing users WARN_DAYS" - ansible.builtin.shell: "awk -F: '/^[^:]+:[^!*]/ && $6< {{ rhel9cis_pass_warn_age }} {print $1}' /etc/shadow" - changed_when: false - failed_when: false - register: discovered_warn_days - - - name: "5.4.1.3 | PATCH | Ensure password expiration warning days is configured | Set existing users WARN_DAYS" - when: - - discovered_warn_days.stdout_lines | length > 0 - - item in prelim_interactive_users | map(attribute='username') | list - - rhel9cis_force_user_warnage - ansible.builtin.command: "chage --warndays {{ rhel9cis_pass_warn_age }} {{ item }}" - changed_when: true - loop: "{{ discovered_warn_days.stdout_lines }}" - -- name: "5.4.1.4 | PATCH | Ensure strong password hashing algorithm is configured" - when: rhel9cis_rule_5_4_1_4 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.4.1.4 - - pam - - NIST800-53R5_IA-5 - ansible.builtin.lineinfile: - path: /etc/login.defs - regexp: '^ENCRYPT_METHOD' - line: 'ENCRYPT_METHOD {{ rhel9cis_passwd_hash_algo | upper }}' - -- name: "5.4.1.5 | PATCH | Ensure inactive password lock is configured" - when: rhel9cis_rule_5_4_1_5 - tags: - - level1-server - - level1-workstation - - patch - - password - - rule_5.4.1.5 - block: - - name: "5.4.1.5 | AUDIT | Ensure inactive password lock is configured | Check current settings" - ansible.builtin.shell: | - useradd -D | grep INACTIVE={{ rhel9cis_inactivelock.lock_days }} | cut -f2 -d= - changed_when: false - failed_when: false - check_mode: false - register: discovered_passwdlck_inactive_settings - - - name: "5.4.1.5 | PATCH | Ensure inactive password lock is configured | Set default inactive setting" - when: discovered_passwdlck_inactive_settings.stdout | length == 0 - ansible.builtin.command: useradd -D -f {{ rhel9cis_inactivelock.lock_days }} - changed_when: true - - - name: "5.4.1.5 | AUDIT | Ensure inactive password lock is 30 days or less | Getting user list" - ansible.builtin.command: "awk -F: '/^[^#:]+:[^\\!\\*:]*:[^:]*:[^:]*:[^:]*:[^:]*:(\\s*|-1|3[1-9]|[4-9][0-9]|[1-9][0-9][0-9]+):[^:]*:[^:]*\\s*$/ {print $1}' /etc/shadow" - changed_when: false - check_mode: false - register: discovered_passwdlck_user_list - - - name: "5.4.1.5 | PATCH | Ensure inactive password lock is 30 days or less | Apply Inactive setting to existing accounts" - when: item in prelim_interactive_users | map(attribute='username') | list - ansible.builtin.command: chage --inactive {{ rhel9cis_inactivelock.lock_days }} "{{ item }}" - changed_when: true - loop: "{{ discovered_passwdlck_user_list.stdout_lines }}" - -- name: "5.4.1.6 | PATCH | Ensure all users last password change date is in the past" - when: rhel9cis_rule_5_4_1_6 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.4.1.6 - vars: - warn_control_id: '5.4.1.6' - block: - - name: "5.4.1.6 | AUDIT | Ensure all users last password change date is in the past | Get current date in Unix Time" - ansible.builtin.shell: echo $(($(date --utc --date "$1" +%s)/86400)) - changed_when: false - failed_when: false - check_mode: false - register: discovered_passwdlck_currentunixtime - - - name: "5.4.1.6 | AUDIT | Ensure all users last password change date is in the past | Get list of users with last changed pw date in the future" - ansible.builtin.shell: "cat /etc/shadow | awk -F: '{if($3>{{ discovered_passwdlck_currentunixtime.stdout }})print$1}'" - changed_when: false - failed_when: false - check_mode: false - register: discovered_passwdlck_user_future - - - name: "5.4.1.6 | AUDIT | Ensure all users last password change date is in the past | Alert on accounts with pw change in the future" - when: - - discovered_passwdlck_user_future.stdout | length > 0 - - not rhel9cis_futurepwchgdate_autofix - ansible.builtin.debug: - msg: "Warning!! The following accounts have the last PW change date in the future: {{ discovered_passwdlck_user_future.stdout_lines }}" - - - name: "5.4.1.6 | AUDIT | Ensure all users last password change date is in the past | warning count" - when: - - discovered_passwdlck_user_future.stdout | length > 0 - - not rhel9cis_futurepwchgdate_autofix - ansible.builtin.import_tasks: - file: warning_facts.yml - - - name: "5.4.1.6 | PATCH | Ensure all users last password change date is in the past | Fix accounts with pw change in the future" - when: - - discovered_passwdlck_user_future.stdout | length > 0 - - rhel9cis_futurepwchgdate_autofix - ansible.builtin.command: passwd --expire {{ item }} - changed_when: true - loop: "{{ discovered_passwdlck_user_future.stdout_lines }}" diff --git a/tasks/section_5/cis_5.4.2.x.yml b/tasks/section_5/cis_5.4.2.x.yml deleted file mode 100644 index b291cc2..0000000 --- a/tasks/section_5/cis_5.4.2.x.yml +++ /dev/null @@ -1,256 +0,0 @@ ---- - -- name: "5.4.2.1 | PATCH | Ensure root is the only UID 0 account" - when: - - rhel9cis_rule_5_4_2_1 - - prelim_uid_zero_accounts_except_root.rc - - rhel9cis_disruption_high - tags: - - level1-server - - level1-workstation - - patch - - accounts - - users - - rule_5.4.2.1 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - ansible.builtin.command: passwd -l {{ item }} - changed_when: false - failed_when: false - loop: "{{ prelim_uid_zero_accounts_except_root.stdout_lines }}" - -- name: "5.4.2.2 | PATCH | Ensure root is the only GID 0 account" - when: - - rhel9cis_rule_5_4_2_2 - - rhel9cis_disruption_high - tags: - - level1-server - - level1-workstation - - patch - - rule_5.4.2.2 - - user - - system - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - block: - - name: "5.4.2.2 | AUDIT | Ensure root is the only GID 0 account | Get members of gid 0" - ansible.builtin.shell: "awk -F: '($1 !~ /^(sync|shutdown|halt|operator)/ && $4==\"0\") {print $1}' /etc/passwd | grep -wv 'root'" - register: discovered_gid0_members - changed_when: false - failed_when: discovered_gid0_members.rc not in [ 0, 1 ] - - - name: "5.4.2.2 | PATCH | Ensure root is the only GID 0 account | Remove users not root from gid 0" - when: - - discovered_gid0_members is defined - - discovered_gid0_members.stdout | length > 0 - ansible.builtin.user: - name: "{{ item }}" - group: root - state: absent - loop: "{{ discovered_gid0_members.stdout_lines }}" - -- name: "5.4.2.3 | AUDIT | Ensure group root is the only GID 0 group" - when: rhel9cis_rule_5_4_2_3 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.4.2.3 - - user - - system - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - block: - - name: "5.4.2.3 | AUDIT | Ensure group root is the only GID 0 group | Get groups with gid 0" - ansible.builtin.shell: "awk -F: '$3==\"0\"{print $1}' /etc/group | grep -vw 'root'" - register: discovered_gid0_groups - changed_when: false - failed_when: discovered_gid0_groups.rc not in [ 0, 1 ] - - - name: "5.4.2.3 | AUDIT | Ensure group root is the only GID 0 group | Warning if others gid 0 groups" - when: - - discovered_gid0_groups is defined - - discovered_gid0_groups.stdout | length > 0 - ansible.builtin.debug: - msg: - - "Warning!! You have other groups assigned to GID 0 - Please resolve" - - "{{ discovered_gid0_groups.stdout_lines }}" - - - name: "5.4.2.3 | WARN | Ensure group root is the only GID 0 group | warn_count" - when: - - discovered_gid0_groups is defined - - discovered_gid0_groups.stdout | length > 0 - ansible.builtin.import_tasks: - file: warning_facts.yml - vars: - warn_control_id: '5.4.2.3' - -- name: "5.4.2.4 | PATCH | Ensure root account access is controlled " - when: rhel9cis_rule_5_4_2_4 - tags: - - level1-server - - level1-workstation - - patch - - shadow_suite - - rule_5.4.2.4 - ansible.builtin.debug: - msg: "This is set as an assert in tasks/main" - -- name: "5.4.2.5 | PATCH | Ensure root PATH Integrity" - when: rhel9cis_rule_5_4_2_5 - tags: - - level1-server - - level1-workstation - - patch - - paths - - rule_5.4.2.5 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - block: - - name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Get root paths" - ansible.builtin.shell: sudo -Hiu root env | grep '^PATH' | cut -d= -f2 - changed_when: false - register: discovered_root_paths - - - name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Get root paths" - when: discovered_root_paths is defined - ansible.builtin.shell: sudo -Hiu root env | grep '^PATH' | cut -d= -f2 | tr ":" "\n" - changed_when: false - register: discovered_root_paths_split - - - name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Set fact" - when: discovered_root_paths is defined - ansible.builtin.set_fact: - root_paths: "{{ discovered_root_paths.stdout }}" - - - name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Check for presence of non-dirs" - ansible.builtin.stat: - path: "{{ item }}" - loop: "{{ discovered_root_paths_split.stdout_lines }}" - register: discovered_root_paths_stat - - - name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Create dirs for some paths that are not dirs" - ansible.builtin.file: - path: "{{ item.item }}" - state: directory - owner: root - group: root - mode: 'go-w' - loop: "{{ discovered_root_paths_stat.results }}" - when: not item.stat.exists - - - name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Check for empty dirs" - when: discovered_root_paths is defined - ansible.builtin.shell: 'echo {{ root_paths }} | grep -q "::" && echo "roots path contains a empty directory (::)"' - changed_when: false - failed_when: discovered_root_path_empty_dir.rc not in [ 0, 1 ] - register: discovered_root_path_empty_dir - - - name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Check for trailing ':'" - when: discovered_root_paths is defined - ansible.builtin.shell: '{{ root_paths }} | cut -d= -f2 | grep -q ":$" && echo "roots path contains a trailing (:)"' - changed_when: false - failed_when: discovered_root_path_trailing_colon.rc not in [ 0, 1 ] - register: discovered_root_path_trailing_colon - - - name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Check for owner and permissions" - when: discovered_root_paths is defined - block: - - name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Check for owner and permissions" - ansible.builtin.stat: - path: "{{ item }}" - register: discovered_root_path_perms - loop: "{{ discovered_root_paths_split.stdout_lines }}" - - - name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Set permissions" - when: - - item.stat.exists - - item.stat.isdir - - item.stat.pw_name != 'root' or item.stat.gr_name != 'root' or item.stat.woth or item.stat.wgrp - - (item != 'root') and (not rhel9cis_uses_root) - ansible.builtin.file: - path: "{{ item.stat.path }}" - state: directory - owner: root - group: root - mode: 'go-w' - follow: false - loop: "{{ discovered_root_path_perms.results }}" - loop_control: - label: "{{ item }}" - -- name: "5.4.2.6 | PATCH | Ensure root user umask is configured" - when: rhel9cis_rule_5_4_2_6 - tags: - - level1-server - - level1-workstation - - patch - - shadow_suite - - rule_5.4.2.6 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.lineinfile: - path: /root/.bash_profile - regexp: \s*umask - line: "umask {{ rhel9cis_root_umask }}" - create: true - mode: 'u-x,go-rwx' - -- name: "5.4.2.7 | PATCH | Ensure system accounts do not have a valid login shell" - when: - - rhel9cis_rule_5_4_2_7 - - "item.id not in prelim_interactive_users | map(attribute='username')" - - item.id not in rhel9cis_system_users_shell - - "'root' not in item.id" - - rhel9cis_disruption_high - tags: - - level1-server - - level1-workstation - - patch - - shadow_suite - - rule_5.4.2.7 - - NIST800-53R5_AC-2 - - NIST800-53R5_AC-3 - - NIST800-53R5_AC-11 - - NIST800-53R5_MP-2 - ansible.builtin.user: - name: "{{ item.id }}" - shell: /usr/sbin/nologin - loop: "{{ prelim_captured_passwd_data }}" - loop_control: - label: "{{ item.id }}" - -- name: "5.4.2.8 | PATCH | Ensure accounts without a valid login shell are locked | Lock accounts" - when: - - rhel9cis_rule_5_4_2_8 - - rhel9cis_disruption_high - - "item.id not in prelim_interactive_users | map(attribute='username')" - - "'root' not in item.id" - tags: - - level1-server - - level1-workstation - - patch - - shadow_suite - - rule_5.4.2.8 - - NIST800-53R5_AC-2 - - NIST800-53R5_AC-3 - - NIST800-53R5_AC-11 - - NIST800-53R5_MP-2 - ansible.builtin.user: - name: "{{ item.id }}" - password_lock: true - loop: "{{ prelim_captured_passwd_data }}" - loop_control: - label: "{{ item.id }}" diff --git a/tasks/section_5/cis_5.4.3.x.yml b/tasks/section_5/cis_5.4.3.x.yml deleted file mode 100644 index 109b6a5..0000000 --- a/tasks/section_5/cis_5.4.3.x.yml +++ /dev/null @@ -1,59 +0,0 @@ ---- - -- name: "5.4.3.1 | PATCH | Ensure nologin is not listed in /etc/shells" - when: rhel9cis_rule_5_4_3_1 - tags: - - level2-server - - level2-workstation - - patch - - shells - - rule_5.4.3.1 - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - ansible.builtin.replace: - path: /etc/shells - regexp: nologin - replace: "" - -- name: "5.4.3.2 | PATCH | Ensure default user shell timeout is configured" - when: rhel9cis_rule_5_4_3_2 - tags: - - level1-server - - level1-workstation - - patch - - shell - - rule_5.4.3.2 - ansible.builtin.blockinfile: - path: "{{ item.path }}" - state: "{{ item.state }}" - marker: "# {mark} - CIS benchmark - Ansible-lockdown" - create: true - mode: 'go-wx' - block: | - TMOUT={{ rhel9cis_shell_session_timeout }} - readonly TMOUT - export TMOUT - loop: - - { path: "{{ rhel9cis_shell_session_file }}", state: present } - - { path: /etc/profile, state: "{{ (rhel9cis_shell_session_file == '/etc/profile') | ternary('present', 'absent') }}" } - -- name: "5.4.3.3 | PATCH | Ensure default user umask is configured" - when: rhel9cis_rule_5_4_3_3 - tags: - - level1-server - - level1-workstation - - patch - - umask - - rule_5.4.3.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.replace: - path: "{{ item.path }}" - regexp: (?i)(umask\s+\d*) - replace: '{{ item.line }} {{ rhel9cis_bash_umask }}' - loop: - - { path: '/etc/profile', line: 'umask' } - - { path: '/etc/login.defs', line: 'UMASK' } diff --git a/tasks/section_5/cis_5.4.x.yml b/tasks/section_5/cis_5.4.x.yml new file mode 100644 index 0000000..cb37024 --- /dev/null +++ b/tasks/section_5/cis_5.4.x.yml @@ -0,0 +1,85 @@ +--- + +- name: "5.4.1 | PATCH | Ensure custom authselect profile is used" + block: + - name: "5.4.1 | AUDIT | Ensure custom authselect profile is used | Gather profiles" + ansible.builtin.shell: 'authselect current | grep "Profile ID: custom/"' + failed_when: false + changed_when: false + check_mode: false + register: rhel9cis_5_4_1_profiles + + - name: "5.4.1 | AUDIT | Ensure custom authselect profile is used | Show profiles" + ansible.builtin.debug: + msg: + - "Below are the current custom profiles" + - "{{ rhel9cis_5_4_1_profiles.stdout_lines }}" + + - name: "5.4.1 | PATCH | Ensure custom authselect profile is used | Create custom profiles" + ansible.builtin.shell: authselect create-profile {{ rhel9cis_authselect['custom_profile_name'] }} -b {{ rhel9cis_authselect['default_file_to_copy'] }} + when: rhel9cis_authselect_custom_profile_create + when: + - rhel9cis_rule_5_4_1 + tags: + - level1-server + - level1-workstation + - manual + - patch + - authselect + - rule_5.4.1 + +- name: "5.4.2 | PATCH | Ensure authselect includes with-faillock | with auth select profile" + block: + - name: "5.4.2 | AUDIT | Ensure authselect includes with-faillock | Gather profiles and enabled features" + ansible.builtin.shell: "authselect current | grep with-faillock" + failed_when: false + changed_when: false + check_mode: false + register: rhel9cis_5_4_2_profiles_faillock + + - name: "5.4.2 | AUDIT | Ensure authselect includes with-faillock | Show profiles" + ansible.builtin.debug: + msg: + - "Below are the current custom profiles" + - "{{ rhel9cis_5_4_2_profiles_faillock.stdout_lines }}" + + - name: "5.4.2 | PATCH | Ensure authselect includes with-faillock | Create custom profiles" + ansible.builtin.shell: "authselect select custom/{{ rhel9cis_authselect['custom_profile_name'] }} with-faillock" + when: rhel9cis_authselect_custom_profile_select + + - name: 5.4.2 | PATCH | Ensure authselect includes with-faillock | not auth select profile" + ansible.builtin.lineinfile: + path: "/etc/pam.d/password-auth" + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + insertbefore: "{{ item.before }}" + loop: + - { 'regexp': '^auth\s+required\s+pam_faillock.so preauth silent deny=.*unlock_time=.*', 'line': 'auth required pam_faillock.so preauth silent deny={{ rhel9cis_pam_faillock.deny }} unlock_time={{ rhel9cis_pam_faillock.unlock_time }}', 'before':'^auth\s+sufficient\s+pam_unix.so try_first_pass'} + - { 'regexp': '^auth\s+required\s+pam_faillock.so authfail deny=.*unlock_time=.*', 'line': 'auth required pam_faillock.so authfail deny={{ rhel9cis_pam_faillock.deny }} unlock_time={{ rhel9cis_pam_faillock.unlock_time }}', 'before':'^auth\s+required\s+pam_deny.so'} + - { 'regexp': '^account\s+required\s+pam_faillock.so', 'line': 'account required pam_faillock.so', 'before':'^account required pam_unix.so'} + when: + - rhel9cis_add_faillock_without_authselect + - rhel9cis_5_4_2_risks == 'ACCEPT' + + - name: 5.4.2 | PATCH | Ensure authselect includes with-faillock | not auth select profile" + ansible.builtin.lineinfile: + path: "/etc/pam.d/system-auth" + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + insertbefore: "{{ item.before | default(omit)}}" + insertafter: "{{ item.after | default(omit)}}" + loop: + - { 'regexp': '^auth\s+required\s+pam_faillock.so preauth silent deny=.*unlock_time=.*', 'line':'auth required pam_faillock.so preauth silent deny={{ rhel9cis_pam_faillock.deny }} unlock_time={{ rhel9cis_pam_faillock.unlock_time }}', 'before':'^auth\s+sufficient\s+pam_unix.so try_first_pass'} + - { 'regexp': '^auth\s+required\s+pam_faillock.so authfail deny=.*unlock_time=.*', 'line': 'auth required pam_faillock.so authfail deny={{ rhel9cis_pam_faillock.deny }} unlock_time={{ rhel9cis_pam_faillock.unlock_time }}', 'before':'^auth\s+required\s+pam_deny.so'} + - { 'regexp': '^account\s+required\s+pam_faillock.so', 'line': 'account required pam_faillock.so', 'before':'^account required pam_unix.so'} + when: + - rhel9cis_add_faillock_without_authselect + - rhel9cis_5_4_2_risks == 'ACCEPT' + when: + - rhel9cis_rule_5_4_2 + tags: + - level1-server + - level1-workstation + - patch + - authselect + - rule_5.4.2 diff --git a/tasks/section_5/cis_5.5.x.yml b/tasks/section_5/cis_5.5.x.yml new file mode 100644 index 0000000..13ac418 --- /dev/null +++ b/tasks/section_5/cis_5.5.x.yml @@ -0,0 +1,98 @@ +--- + +- name: "5.5.1 | PATCH | Ensure password creation requirements are configured" + block: + - name: "5.5.1 | PATCH | Ensure password creation requirements are configured | Set pwquality config settings" + ansible.builtin.lineinfile: + path: /etc/security/pwquality.conf + regexp: ^{{ item.name }} + line: "{{ item.name }} = {{ item.value }}" + loop: + - { name: minlen, value: "{{ rhel9cis_pam_password.minlen }}" } + - { name: minclass, value: "{{ rhel9cis_pam_password.minclass }}" } + + - name: "5.5.1 | PATCH | Ensure password creation requirements are configured | Set system-auth retry settings" + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + regexp: '^password\s*requisite\s*pam_pwquality.so' + line: "password requisite pam_pwquality.so try_first_pass local_users_only enforce_for_root retry=3" + insertbefore: '^#?password ?' + + - name: "5.5.1 | PATCH | Ensure password creation requirements are configured | Set system-auth retry settings" + ansible.builtin.lineinfile: + path: /etc/pam.d/password-auth + regexp: '^password\s*requisite\s*pam_pwquality.so' + line: "password requisite pam_pwquality.so try_first_pass local_users_only enforce_for_root retry=3" + insertbefore: '^#?password ?' + when: + - rhel9cis_rule_5_5_1 + tags: + - level1-server + - level1-workstation + - patch + - rule_5.5.1 + +- name: "5.5.2 | PATCH | Ensure lockout for failed password attempts is configured" + ansible.builtin.lineinfile: + path: /etc/security/faillock.conf + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + loop: + - { regexp: '^\s*deny\s*=\s*[1-5]\b', line: 'deny = 5' } + - { regexp: '^\s*unlock_time\s*=\s*(0|9[0-9][0-9]|[1-9][0-9][0-9][0-9]+)\b', line: 'unlock_time = 900' } + when: + - rhel9cis_rule_5_5_2 + +- name: "5.5.3 | PATCH | Ensure password reuse is limited" + block: + - name: "5.5.3 | PATCH | Ensure password reuse is limited | pwquality" + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + line: "password requisite pam_pwhistory.so try_first_pass local_users_only enforce_for_root retry=3 remember={{ rhel9cis_pam_faillock.remember }}" + insertafter: '^password\s*requisite\s*pam_pwquality.so' + + - name: "5.5.3 | PATCH | Ensure password reuse is limited | pam_unix" + ansible.builtin.replace: + path: /etc/pam.d/system-auth + regexp: '^password\s*(sufficient|requisite|sufficient)\s*pam_unix.so.*$' + replace: 'password requisite pam_unix.so sha512 shadow try_first_pass use_authtok remember={{ rhel9cis_pam_faillock.remember }}' + when: + - rhel9cis_rule_5_5_3 + tags: + - level1-server + - level1-workstation + - patch + - rule_5.5.3 + +- name: "5.5.4 | PATCH | Ensure password hashing algorithm is SHA-512 or yescrypt" + block: + - name: "5.5.4 | PATCH | Ensure password hashing algorithm is SHA-512 | libuser.conf" + ansible.builtin.replace: + path: /etc/libuser.conf + regexp: '^crypt_style\s*=\s*.*$' + replace: 'crypt_style = sha512' + + - name: "5.5.4 | PATCH | Ensure password hashing algorithm is SHA-512 | login.defs" + ansible.builtin.replace: + path: /etc/login.defs + regexp: '^ENCRYPT_METHOD.*' + replace: 'ENCRYPT_METHOD SHA512' + + - name: "5.5.4 | PATCH | Ensure password hashing algorithm is SHA-512 | password-auth" + ansible.builtin.replace: + path: /etc/pam.d/password-auth + regexp: '^password\s*sufficient\s*pam_unix.so.*$' + replace: 'password sufficient pam_unix.so sha512 shadow try_first_pass use_authtok remember={{ rhel9cis_pam_faillock.remember }}' + + - name: "5.5.4 | PATCH | Ensure password hashing algorithm is SHA-512 | system-auth" + ansible.builtin.replace: + path: /etc/pam.d/system-auth + regexp: '^password\s*sufficient\s*pam_unix.so.*$' + replace: 'password sufficient pam_unix.so sha512 shadow try_first_pass use_authtok remember={{ rhel9cis_pam_faillock.remember }}' + when: + - rhel9cis_rule_5_5_4 + tags: + - level1-server + - level1-workstation + - patch + - rule_5.5.4 diff --git a/tasks/section_5/cis_5.6.1.x.yml b/tasks/section_5/cis_5.6.1.x.yml new file mode 100644 index 0000000..141c013 --- /dev/null +++ b/tasks/section_5/cis_5.6.1.x.yml @@ -0,0 +1,119 @@ +--- + +- name: "5.6.1.1 | PATCH | Ensure password expiration is 365 days or less" + ansible.builtin.lineinfile: + path: /etc/login.defs + regexp: '^PASS_MAX_DAYS' + line: "PASS_MAX_DAYS {{ rhel9cis_pass['max_days'] }}" + when: + - rhel9cis_rule_5_6_1_1 + tags: + - level1-server + - level1-workstation + - patch + - password + - rule_5.5.1.1 + +- name: "5.6.1.2 | PATCH | Ensure minimum days between password changes is 7 or more" + ansible.builtin.lineinfile: + path: /etc/login.defs + regexp: '^PASS_MIN_DAYS' + line: "PASS_MIN_DAYS {{ rhel9cis_pass['min_days'] }}" + when: + - rhel9cis_rule_5_6_1_2 + tags: + - level1-server + - level1-workstation + - patch + - password + - rule_5.6.1.2 + +- name: "5.6.1.3 | PATCH | Ensure password expiration warning days is 7 or more" + ansible.builtin.lineinfile: + path: /etc/login.defs + regexp: '^PASS_WARN_AGE' + line: "PASS_WARN_AGE {{ rhel9cis_pass['warn_age'] }}" + when: + - rhel9cis_rule_5_6_1_3 + tags: + - level1-server + - level1-workstation + - patch + - password + - rule_5.5.1.3 + +- name: "5.6.1.4 | PATCH | Ensure inactive password lock is 30 days or less" + block: + - name: "5.6.1.4 | AUDIT | Ensure inactive password lock is 30 days or less | Check current settings" + ansible.builtin.shell: useradd -D | grep INACTIVE={{ rhel9cis_inactivelock.lock_days }} | cut -f2 -d= + changed_when: false + failed_when: false + check_mode: false + register: rhel9cis_5_6_1_4_inactive_settings + + - name: "5.6.1.4 | PATCH | Ensure inactive password lock is 30 days or less | Set default inactive setting" + ansible.builtin.shell: useradd -D -f {{ rhel9cis_inactivelock.lock_days }} + when: rhel9cis_5_6_1_4_inactive_settings.stdout | length == 0 + + - name: "5.6.1.4 | AUDIT | Ensure inactive password lock is 30 days or less | Getting user list" + ansible.builtin.shell: "awk -F: '/^[^#:]+:[^\\!\\*:]*:[^:]*:[^:]*:[^:]*:[^:]*:(\\s*|-1|3[1-9]|[4-9][0-9]|[1-9][0-9][0-9]+):[^:]*:[^:]*\\s*$/ {print $1}' /etc/shadow" + changed_when: false + check_mode: false + register: rhel9cis_5_6_1_4_user_list + + - name: "5.6.1.4 | PATCH | Ensure inactive password lock is 30 days or less | Apply Inactive setting to existing accounts" + ansible.builtin.shell: chage --inactive {{ rhel9cis_inactivelock.lock_days }} "{{ item }}" + loop: "{{ rhel9cis_5_6_1_4_user_list.stdout_lines }}" + when: + - rhel9cis_rule_5_6_1_4 + tags: + - level1-server + - level1-workstation + - patch + - password + - rule_5.6.1.4 + +- name: "5.6.1.5 | PATCH | Ensure all users last password change date is in the past" + block: + - name: "5.6.1.5 | AUDIT | Ensure all users last password change date is in the past | Get current date in Unix Time" + ansible.builtin.shell: echo $(($(date --utc --date "$1" +%s)/86400)) + changed_when: false + failed_when: false + check_mode: false + register: rhel9cis_5_6_1_5_currentut + + - name: "5.6.1.5 | AUDIT | Ensure all users last password change date is in the past | Get list of users with last changed pw date in the future" + ansible.builtin.shell: "cat /etc/shadow | awk -F: '{if($3>{{ rhel9cis_5_6_1_5_currentut.stdout }})print$1}'" + changed_when: false + failed_when: false + check_mode: false + register: rhel9cis_5_6_1_5_user_list + + - name: "5.6.1.5 | AUDIT | Ensure all users last password change date is in the past | Alert on accounts with pw change in the future" + ansible.builtin.debug: + msg: "Warning!! The following accounts have the last PW change date in the future: {{ rhel9cis_5_6_1_5_user_list.stdout_lines }}" + when: + - rhel9cis_5_6_1_5_user_list.stdout | length > 0 + - not rhel9cis_futurepwchgdate_autofix + + - name: "5.6.1.5 | AUDIT | Ensure all users last password change date is in the past | warning count" + ansible.builtin.import_tasks: warning_facts.yml + when: + - rhel9cis_5_6_1_5_user_list.stdout | length > 0 + - not rhel9cis_futurepwchgdate_autofix + + - name: "5.6.1.5 | PATCH | Ensure all users last password change date is in the past | Fix accounts with pw change in the future" + ansible.builtin.shell: passwd --expire {{ item }} + when: + - rhel9cis_5_6_1_5_user_list.stdout | length > 0 + - rhel9cis_futurepwchgdate_autofix + loop: "{{ rhel9cis_5_6_1_5_user_list.stdout_lines }}" + vars: + warn_control_id: '5.6.1.5' + when: + - rhel9cis_rule_5_6_1_5 + tags: + - level1-server + - level1-workstation + - patch + - rule_5.5.1.5 diff --git a/tasks/section_5/cis_5.6.x.yml b/tasks/section_5/cis_5.6.x.yml new file mode 100644 index 0000000..56b3d5f --- /dev/null +++ b/tasks/section_5/cis_5.6.x.yml @@ -0,0 +1,125 @@ +--- + +- name: "5.6.2 | PATCH | Ensure system accounts are secured" + block: + - name: "5.6.2 | Ensure system accounts are secured | Set nologin" + ansible.builtin.user: + name: "{{ item.id }}" + shell: /usr/sbin/nologin + loop: "{{ rhel9cis_passwd }}" + when: + - item.id != "root" + - item.id != "sync" + - item.id != "shutdown" + - item.id != "halt" + - item.id != "nfsnobody" + - item.gid < min_int_uid | int + - item.shell != " /bin/false" + - item.shell != " /usr/sbin/nologin" + loop_control: + label: "{{ item.id }}" + + - name: "5.6.2 | PATCH | Ensure system accounts are secured | Lock accounts" + ansible.builtin.user: + name: "{{ item.id }}" + password_lock: true + loop: "{{ rhel9cis_passwd }}" + when: + - item.id != "halt" + - item.id != "shutdown" + - item.id != "sync" + - item.id != "root" + - item.id != "nfsnobody" + - item.gid < min_int_uid | int + - item.shell != " /bin/false" + - item.shell != " /usr/sbin/nologin" + loop_control: + label: "{{ item.id }}" + when: + - rhel9cis_rule_5_6_2 + tags: + - level1-server + - level1-workstation + - patch + - accounts + - rule_5.6.2 + +- name: "5.6.3 | PATCH | Ensure default user shell timeout is 900 seconds or less" + ansible.builtin.blockinfile: + path: "{{ item.path }}" + state: "{{ item.state }}" + marker: "# {mark} - CIS benchmark - Ansible-lockdown" + create: true + mode: 0644 + block: | + TMOUT={{ rhel9cis_shell_session_timeout.timeout }} + export TMOUT + readonly TMOUT + loop: + - { path: "{{ rhel9cis_shell_session_timeout.file }}", state: present } + - { path: /etc/profile, state: "{{ (rhel9cis_shell_session_timeout.file == '/etc/profile') | ternary('present', 'absent') }}" } + when: + - rhel9cis_rule_5_6_3 + tags: + - level1-server + - level1-workstation + - patch + - accounts + - rule_5.6.3 + +- name: "5.6.4 | PATCH | Ensure default group for the root account is GID 0" + ansible.builtin.user: + name: root + group: 0 + when: + - rhel9cis_rule_5_6_4 + tags: + - level1-server + - level1-workstation + - patch + - accounts + - rule_5.6.4 + +- name: "5.6.5 | PATCH | Ensure default user umask is 027 or more restrictive" + block: + - name: "5.6.5 | PATCH | Ensure default user umask is 027 or more restrictive | Set umask for /etc/login.defs pam_umask settings" + ansible.builtin.replace: + path: /etc/login.defs + regexp: "{{ item.regexp }}" + replace: "{{ item.replace }}" + loop: + - { regexp: '(UMASK\s+)0[012][0-6]', replace: '\1 027' } + - { regexp: '(USERGROUPS_ENAB\s+)yes', replace: '\1 no' } + + - name: "5.6.5 | PATCH | Ensure default user umask is 027 or more restrictive | Set umask for /etc/bashrc" + ansible.builtin.replace: + path: /etc/bashrc + regexp: '^(?i)(\s+UMASK|UMASK)\s0[0-2][0-6]' + replace: '\1 027' + + - name: "5.6.5 | PATCH | Ensure default user umask is 027 or more restrictive | Set umask for /etc/profile" + ansible.builtin.replace: + path: /etc/profile + regexp: '^(?i)(\s+UMASK|UMASK)\s0[0-2][0-6]' + replace: '\1 027' + when: + - rhel9cis_rule_5_6_5 + tags: + - level1-server + - level1-workstation + - patch + - accounts + - rule_5.6.5 + +- name: "5.6.6 | PATCH | Ensure root password is set" + ansible.builtin.debug: + msg: "The root password has been set as per the assert in early stages" + when: + - rhel9cis_rule_5_6_6 + tags: + - level1-server + - level1-workstation + - patch + - accounts + - root + - rule_5.6.6 diff --git a/tasks/section_5/main.yml b/tasks/section_5/main.yml index 09a2fdd..5aed1c1 100644 --- a/tasks/section_5/main.yml +++ b/tasks/section_5/main.yml @@ -2,59 +2,25 @@ # Access, Authentication, and Authorization -- name: "SECTION | 5.1 | Configure SSH Server" +- name: "SECTION | 5.1 | Configure time-based job schedulers" + ansible.builtin.import_tasks: cis_5.1.x.yml + +- name: "SECTION | 5.2 | Configure SSH Server" + ansible.builtin.import_tasks: cis_5.2.x.yml when: - - "'openssh-server' in ansible_facts.packages" - - rhel9cis_section5_1 - ansible.builtin.import_tasks: - file: cis_5.1.x.yml + - "'openssh-server' in ansible_facts.packages" -- name: "SECTION | 5.2 | Configure privilege escalation" - when: - - rhel9cis_section5_2 - ansible.builtin.import_tasks: - file: cis_5.2.x.yml +- name: "SECTION | 5.3 | Configure privilege escalation" + ansible.builtin.import_tasks: cis_5.3.x.yml -- name: "SECTION | 5.3" - when: - - rhel9cis_section5_3 - block: - - name: "SECTION | 5.3.1.x | Configure PAM software packages" - ansible.builtin.import_tasks: - file: cis_5.3.1.x.yml +- name: "SECTION | 5.4 | Configure authselect" + ansible.builtin.import_tasks: cis_5.4.x.yml - - name: "SECTION | 5.3.2.x | Configure authselect" - ansible.builtin.import_tasks: - file: cis_5.3.2.x.yml +- name: "SECTION | 5.5 | Configure PAM " + ansible.builtin.import_tasks: cis_5.5.x.yml - - name: "SECTION | 5.3.3.1.x | Configure pam_faillock module" - ansible.builtin.import_tasks: - file: cis_5.3.3.1.x.yml +- name: "SECTION | 5.6.1.x | Shadow Password Suite Parameters" + ansible.builtin.import_tasks: cis_5.6.1.x.yml - - name: "SECTION | 5.3.3.2.x | Configure pam_pwquality module" - ansible.builtin.import_tasks: - file: cis_5.3.3.2.x.yml - - - name: "SECTION | 5.3.3.3.x | Configure pam_pwhistory module" - ansible.builtin.import_tasks: - file: cis_5.3.3.3.x.yml - - - name: "SECTION | 5.3.3.4.x | Configure pam_unix module" - ansible.builtin.import_tasks: - file: cis_5.3.3.4.x.yml - -- name: "SECTION | 5.4" - when: - - rhel9cis_section5_4 - block: - - name: "SECTION | 5.4.1.x | Configure shadow password suite parameters" - ansible.builtin.import_tasks: - file: cis_5.4.1.x.yml - - - name: "SECTION | 5.4.2.x | Configure root and system accounts and environment" - ansible.builtin.import_tasks: - file: cis_5.4.2.x.yml - - - name: "SECTION | 5.4.3.x | Configure user default environment" - ansible.builtin.import_tasks: - file: cis_5.4.3.x.yml +- name: "SECTION | 5.6.x | Misc. User Account Settings" + ansible.builtin.import_tasks: cis_5.6.x.yml diff --git a/tasks/section_6/cis_6.1.x.yml b/tasks/section_6/cis_6.1.x.yml index a29118a..298492d 100644 --- a/tasks/section_6/cis_6.1.x.yml +++ b/tasks/section_6/cis_6.1.x.yml @@ -1,129 +1,346 @@ --- -- name: "6.1.1 | PATCH | Ensure AIDE is installed" +- name: "6.1.1 | PATCH | Ensure permissions on /etc/passwd are configured" + ansible.builtin.file: + path: /etc/passwd + owner: root + group: root + mode: 0644 when: - - rhel9cis_config_aide - - rhel9cis_rule_6_1_1 + - rhel9cis_rule_6_1_1 tags: - - level1-server - - level1-workstation - - aide - - patch - - rule_6.1.1 - - NIST800-53R5_AU-2 + - level1-server + - level1-workstation + - patch + - permissions + - rule_6.1.1 + +- name: "6.1.2 | PATCH | Ensure permissions on /etc/passwd- are configured" + ansible.builtin.file: + path: /etc/passwd- + owner: root + group: root + mode: 0644 + when: + - rhel9cis_rule_6_1_2 + tags: + - level1-server + - level1-workstation + - patch + - permissions + - rule_6.1.2 + +- name: "6.1.3 | PATCH | Ensure permissions on /etc/group are configured" + ansible.builtin.file: + path: /etc/group- + owner: root + group: root + mode: 0644 + when: + - rhel9cis_rule_6_1_3 + tags: + - level1-server + - level1-workstation + - patch + - permissions + - rule_6.1.3 + +- name: "6.1.4 | PATCH | Ensure permissions on /etc/group- are configured" + ansible.builtin.file: + path: /etc/group- + owner: root + group: root + mode: 0644 + when: + - rhel9cis_rule_6_1_4 + tags: + - level1-server + - level1-workstation + - patch + - permissionss + - rule_6.1.4 + +- name: "6.1.5 | PATCH | Ensure permissions on /etc/shadow are configured" + ansible.builtin.file: + path: /etc/shadow + owner: root + group: root + mode: 0000 + when: + - rhel9cis_rule_6_1_5 + tags: + - level1-server + - level1-workstation + - patch + - permissions + - rule_6.1.5 + +- name: "6.1.6 | PATCH | Ensure permissions on /etc/shadow- are configured" + ansible.builtin.file: + path: /etc/shadow- + owner: root + group: root + mode: 0000 + when: + - rhel9cis_rule_6_1_6 + tags: + - level1-server + - level1-workstation + - patch + - permissions + - rule_6.1.6 + +- name: "6.1.7 | PATCH | Ensure permissions on /etc/gshadow are configured" + ansible.builtin.file: + path: /etc/gshadow + owner: root + group: root + mode: 0000 + when: + - rhel9cis_rule_6_1_7 + tags: + - level1-server + - level1-workstation + - patch + - permissions + - rule_6.1.7 + +- name: "6.1.8 | PATCH | Ensure permissions on /etc/gshadow- are configured" + ansible.builtin.file: + path: /etc/gshadow- + owner: root + group: root + mode: 0000 + when: + - rhel9cis_rule_6_1_8 + tags: + - level1-server + - level1-workstation + - patch + - permissions + - rule_6.1.10 + +- name: "6.1.9 | PATCH | Ensure no world writable files exist" block: - - name: "6.1.1 | PATCH | Ensure AIDE is installed" - ansible.builtin.package: - name: "{{ aide_packages }}" - state: present - update_cache: true - register: discovered_aide_pkg_added + - name: "6.1.9 | AUDIT | Ensure no world writable files exist | Get list of world-writable files" + ansible.builtin.shell: df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -0002 + failed_when: false + changed_when: false + register: rhel_09_6_1_9_perms_results - - name: "6.1.1 | PATCH | Ensure AIDE is installed | Recapture packages" - when: discovered_aide_pkg_added.skipped is not defined - ansible.builtin.package_facts: - manager: auto - - - name: "6.1.1 | AUDIT | Ensure AIDE is installed | Check file exists" - ansible.builtin.stat: - path: "{{ rhel9cis_aide_db_file }}" - register: discovered_aide_db_file - - - name: "6.1.1 | AUDIT | Ensure AIDE is installed | Check current db file age" - when: discovered_aide_db_file.stat.exists - ansible.builtin.find: - path: "{{ rhel9cis_aide_db_file | dirname }}" - pattern: "{{ rhel9cis_aide_db_file | basename }}" - age: "{{ rhel9cis_aide_db_file_age }}" - register: discovered_aide_db_age - - - name: "6.1.1 | PATCH | Ensure AIDE is installed | Configure AIDE" - when: - - not ansible_check_mode - - not discovered_aide_db_file.stat.exists or - (discovered_aide_db_age.files | length > 0) or - rhel9cis_aide_db_recreate - block: - - name: "6.1.1 | PATCH | Ensure AIDE is installed | Build AIDE DB" - ansible.builtin.command: "{{ aide_initiate_command }}" - changed_when: true - - - name: "6.1.1 | PATCH | Ensure AIDE is installed | Build AIDE DB | Wait for file before continuing" - ansible.builtin.wait_for: - path: /var/lib/aide/aide.db.new.gz - - - name: "6.1.1 | PATCH | Ensure AIDE is installed | Build AIDE DB |copy AIDE DB" - ansible.builtin.copy: - src: /var/lib/aide/aide.db.new.gz - dest: /var/lib/aide/aide.db.gz - remote_src: true - mode: 'ug-wx,o-rwx' - register: aide_db_cp - failed_when: - - not ansible_check_mode - - aide_db_cp.failed - -- name: "6.1.2 | PATCH | Ensure filesystem integrity is regularly checked" + - name: "6.1.9 | PATCH | Ensure no world writable files exist | Adjust world-writable files if they exist (Configurable)" + ansible.builtin.file: + path: '{{ item }}' + mode: o-w + state: touch + loop: "{{ rhel_09_6_1_9_perms_results.stdout_lines }}" + when: + - rhel_09_6_1_9_perms_results.stdout_lines is defined + - rhel9cis_no_world_write_adjust when: - - rhel9cis_rule_6_1_2 - - not system_is_ec2 + - rhel9cis_rule_6_1_9 tags: - - level1-server - - level1-workstation - - aide - - file_integrity - - patch - - rule_6.1.2 - - NIST800-53R5_AU-2 + - level1-server + - level1-workstation + - patch + - files + - permissions + - rule_6.1.9 + +- name: "6.1.10 | AUDIT | Ensure no unowned files or directories exist" block: - - name: "6.1.2 | PATCH | Ensure filesystem integrity is regularly checked" - when: rhel9cis_aide_scan == "cron" - ansible.builtin.cron: - name: Run AIDE integrity check - cron_file: "{{ rhel9cis_aide_cron['cron_file'] }}" - user: "{{ rhel9cis_aide_cron['cron_user'] }}" - minute: "{{ rhel9cis_aide_cron['aide_minute'] | default('0') }}" - hour: "{{ rhel9cis_aide_cron['aide_hour'] | default('5') }}" - day: "{{ rhel9cis_aide_cron['aide_day'] | default('*') }}" - month: "{{ rhel9cis_aide_cron['aide_month'] | default('*') }}" - weekday: "{{ rhel9cis_aide_cron['aide_weekday'] | default('*') }}" - job: "{{ rhel9cis_aide_cron['aide_job'] }}" + - name: "6.1.10 | AUDIT | Ensure no unowned files or directories exist | Finding all unowned files or directories" + ansible.builtin.shell: find "{{ item.mount }}" -xdev -nouser + changed_when: false + failed_when: false + check_mode: false + register: rhel_09_6_1_10_audit + loop: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.mount }}" + when: item['device'].startswith('/dev') and not 'bind' in item['options'] - - name: "6.1.2 | PATCH | Ensure filesystem integrity is regularly checked | aide service" - when: rhel9cis_aide_scan == "timer" - ansible.builtin.systemd: - name: aidecheck.service - enabled: true + - name: "6.1.10 | AUDIT | Ensure no unowned files or directories exist | Displaying any unowned files or directories" + ansible.builtin.debug: + msg: "Warning !! Manual intervention is required -- missing owner on items in {{ item.item.mount }}: {{ item.stdout_lines | join(', ') }}" + loop: "{{ rhel_09_6_1_10_audit.results }}" + when: + - item.stdout_lines is defined + - item.stdout_lines | length > 0 - - name: "6.1.2 | PATCH | Ensure filesystem integrity is regularly checked | aide service" - when: rhel9cis_aide_scan == "timer" - ansible.builtin.systemd: - name: aidecheck.timer - state: started - enabled: true + - name: "6.1.10 | AUDIT | Ensure no unowned files or directories exist | warning" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '6.1.10' + when: + - item.stdout_lines is defined + - item.stdout_lines | length > 0 -- name: "6.1.3 | PATCH | Ensure cryptographic mechanisms are used to protect the integrity of audit tools" when: - - rhel9cis_rule_6_1_3 - - not system_is_ec2 + - rhel9cis_rule_6_1_10 tags: - - level1-server - - level1-workstation - - aide - - file_integrity - - patch - - rule_6.1.3 - ansible.builtin.blockinfile: - path: /etc/aide.conf - marker: "# {mark} Audit tools - CIS benchmark - Ansible-lockdown" - block: | - /usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512 - /usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512 - /usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512 - /usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512 - /usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512 - /usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512 - register: aide_file_integrity_check - failed_when: - - not ansible_check_mode - - aide_file_integrity_check.failed + - level1-server + - level1-workstation + - audit + - files + - permissions + - rule_6.1.10 + +- name: "6.1.11 | AUDIT | Ensure no ungrouped files or directories exist" + block: + - name: "6.1.11 | AUDIT | Ensure no ungrouped files or directories exist | Finding all ungrouped files or directories" + ansible.builtin.shell: find "{{ item.mount }}" -xdev -nogroup + check_mode: false + failed_when: false + changed_when: false + register: rhel_09_6_1_11_audit + loop: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.mount }}" + when: item['device'].startswith('/dev') and not 'bind' in item['options'] + + - name: "6.1.11 | AUDIT | Ensure no ungrouped files or directories exist | Displaying all ungrouped files or directories" + ansible.builtin.debug: + msg: "Warning !! Manual intervention is required -- missing group on items in {{ item.item.mount }}: {{ item.stdout_lines | join(', ') }}" + loop: "{{ rhel_09_6_1_11_audit.results }}" + when: + - item.stdout_lines is defined + - item.stdout_lines | length > 0 + + - name: "6.1.11 | AUDIT | Ensure no ungrouped files or directories exist | warning" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '6.1.11' + when: + - item.stdout_lines is defined + - item.stdout_lines | length > 0 + when: + - rhel9cis_rule_6_1_11 + tags: + - level1-server + - level1-workstation + - audit + - files + - permissions + - rule_6.1.11 + +- name: "6.1.12 | PATCH | Ensure sticky bit is set on all world-writable directories" + ansible.builtin.shell: df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type d -perm -0002 2>/dev/null | xargs chmod a+t + changed_when: false + failed_when: false + when: + - rhel9cis_rule_6_1_12 + tags: + - level1-server + - level1-workstation + - patch + - stickybits + - permissons + - rule_1.1.21 + +- name: "6.1.13 | AUDIT | Audit SUID executables" + block: + - name: "6.1.13 | AUDIT | Audit SUID executables | Find all SUID executables" + ansible.builtin.shell: df {{ item.mount }} -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -4000 + failed_when: false + changed_when: false + register: rhel_09_6_1_13_perms_results + loop: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.mount }}" + + - name: "6.1.13 | AUDIT | Audit SUID executables | Alert SUID executables exist" + ansible.builtin.debug: + msg: "Warning!! Manual intervention is required -- SUID set on items in {{ item.item.mount }}: {{ item.stout_lines | join(', ') }}" + loop: "{{ rhel_09_6_1_13_perms_results.stdout_lines }}" + when: + - rhel_09_6_1_13_perms_results.stdout is defined + + - name: "6.1.13 | AUDIT | Audit SUID executables | Alert SUID executables exist | warning" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '6.1.13' + when: + - rhel_09_6_1_13_perms_results.stdout is defined + when: + - rhel9cis_rule_6_1_13 + tags: + - level1-server + - level1-workstation + - manual + - audit + - files + - rule_6.1.13 + +- name: "6.1.14 | AUDIT | Audit SGID executables" + block: + - name: "6.1.14 | AUDIT | Audit SGID executables | Find all SGID executables" + ansible.builtin.shell: df {{ item.mount }} -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -2000 + failed_when: false + changed_when: false + register: rhel_09_6_1_14_perms_results + loop: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.mount }}" + + - name: "6.1.14 | AUDIT | Audit SGID executables | Alert SGID executables exist" + ansible.builtin.debug: + msg: "Manual intervention is required -- SGID set on items in {{ item.item.mount }}: {{ item.stout_lines | join(', ') }}" + loop: "{{ rhel_09_6_1_14_perms_results.stdout_lines }}" + when: + - rhel_09_6_1_14_perms_results.stdout is defined + + - name: "6.1.14 | AUDIT | Audit SGID executables| warning" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '6.1.14' + when: + - rhel_09_6_1_14_perms_results.stdout is defined + when: + - rhel9cis_rule_6_1_14 + tags: + - level1-server + - level1-workstation + - manual + - audit + - files + - rule_6.1.14 + +- name: "6.1.15 | AUDIT | Audit system file permissions" + block: + - name: "6.1.15 | AUDIT | Audit system file permissions | Audit the packages" + ansible.builtin.shell: rpm -Va --nomtime --nosize --nomd5 --nolinkto + changed_when: false + failed_when: false + register: rhel9cis_6_1_15_packages_rpm + + - name: "6.1.15 | AUDIT | Audit system file permissions | Create list and warning" + block: + - name: "6.1.15 | AUDIT | Audit system file permissions | Add file discrepancy list to system" + ansible.builtin.copy: + dest: "{{ rhel9cis_rpm_audit_file }}" # noqa template-instead-of-copy + content: "{{ rhel9cis_6_1_15_packages_rpm.stdout }}" + owner: root + group: root + mode: 0640 + + - name: "6.1.15 | AUDIT | Audit system file permissions | Message out alert for package descrepancies" + ansible.builtin.debug: + msg: | + "Warning!! You have some package descrepancies issues. + The file list can be found in {{ rhel9cis_rpm_audit_file }}" + + - name: "6.1.15 | AUDIT | Audit system file permissions | warning count" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '6.1.15' + when: rhel9cis_6_1_15_packages_rpm.stdout|length > 0 + when: + - rhel9cis_rule_6_1_15 + tags: + - level2-server + - level2-workstation + - manual + - audit + - permissions + - rule_6.1.15 diff --git a/tasks/section_6/cis_6.2.1.x.yml b/tasks/section_6/cis_6.2.1.x.yml deleted file mode 100644 index fa75880..0000000 --- a/tasks/section_6/cis_6.2.1.x.yml +++ /dev/null @@ -1,115 +0,0 @@ ---- - -- name: "6.2.1.1 | PATCH | Ensure journald service is enabled and active" - when: rhel9cis_rule_6_2_1_1 - tags: - - level1-server - - level1-workstation - - audit - - journald - - rule_6.2.1.1 - ansible.builtin.systemd: - name: systemd-journald.service - masked: false - state: started - -- name: "6.2.1.2 | PATCH | Ensure journald log file access is configured" - when: rhel9cis_rule_6_2_1_2 - tags: - - level1-server - - level1-workstation - - audit - - journald - - rule_6.2.1.2 - block: - - name: "6.2.1.2 | PATCH | Ensure journald log file access is configured | Default file permissions" - ansible.builtin.file: - path: /usr/lib/tmpfiles.d/systemd.conf - mode: 'g-wx,o-rwx' - - - name: "6.2.1.2 | AUDIT | Ensure journald log file access is configured | Check for override file" - ansible.builtin.stat: - path: /etc/tmpfiles.d/systemd.conf - register: discovered_tmpfile_override - - - name: "6.2.1.2 | AUDIT | Ensure journald log file access is configured | If override file check for journal" - when: discovered_tmpfile_override.stat.exists - ansible.builtin.shell: grep -E 'z /var/log/journal/%m/system.journal \d*' /usr/lib/tmpfiles.d/systemd.conf - register: discovered_journald_fileperms_override - changed_when: false - failed_when: discovered_journald_fileperms_override.rc not in [ 0, 1 ] - - - name: "6.2.1.2 | AUDIT | Ensure journald log file access is configured | Warning if override found" - when: - - discovered_tmpfile_override.stat.exists - - discovered_journald_fileperms_override.stdout | length > 0 - ansible.builtin.debug: - msg: "Warning!! - tmpfiles override found /usr/lib/tmpfiles.d/systemd.conf affecting journald files please confirm matches site policy" - - - name: "6.2.1.2 | AUDIT | Ensure journald log file access is configured | Warning if override found" - when: - - discovered_tmpfile_override.stat.exists - - discovered_journald_fileperms_override.stdout | length > 0 - ansible.builtin.import_tasks: - file: warning_facts.yml - vars: - warn_control_id: '6.2.1.2' - -- name: "6.2.1.3 | PATCH | Ensure journald log file rotation is configured" - when: rhel9cis_rule_6_2_1_3 - tags: - - level1-server - - level1-workstation - - patch - - journald - - rule_6.2.1.3 - notify: Restart journald - block: - - name: "6.2.1.3 | PATCH | Ensure journald log file rotation is configured | Add file" - ansible.builtin.template: - src: etc/systemd/journald.conf.d/rotation.conf.j2 - dest: /etc/systemd/journald.conf.d/rotation.conf - owner: root - group: root - mode: 'g-wx,o-rwx' - - - name: "6.2.1.3 | PATCH | Ensure journald log file rotation is configured | comment out current entries" - ansible.builtin.replace: - path: /etc/systemd/journald.conf - regexp: "{{ item }}" - replace: '#\1' - loop: - - '^(\s*SystemMaxUse\s*=.*)' - - '^(\s*SystemKeepFree\s*=.*)' - - '^(\s*RuntimeMaxUse\s*=)' - - '^(\s*RuntimeKeepFree\s*=.*)' - - '^(\s*MaxFileSec\s*=.*)' - -- name: "6.2.1.4 | PATCH | Ensure only one logging system is in use" - when: rhel9cis_rule_6_2_1_4 - tags: - - level1-server - - level1-workstation - - patch - - journald - - syslog - - rule_6.2.1.4 - block: - - name: "6.2.1.4 | PATCH | Ensure only one logging system is in use | when rsyslog" - when: - - rhel9cis_syslog == "rsyslog" - - "'systemd-journald' in ansible_facts.packages" - ansible.builtin.systemd: - name: systemd-journald - state: stopped - enabled: false - - - name: "6.2.1.4 | PATCH | Ensure only one logging system is in use | when journald" - when: - - rhel9cis_syslog == "journald" - - "'rsyslog' in ansible_facts.packages" - ansible.builtin.systemd: - name: rsyslog - state: stopped - enabled: false - register: discovered_rsyslog_service diff --git a/tasks/section_6/cis_6.2.2.1.x.yml b/tasks/section_6/cis_6.2.2.1.x.yml deleted file mode 100644 index aa2415d..0000000 --- a/tasks/section_6/cis_6.2.2.1.x.yml +++ /dev/null @@ -1,80 +0,0 @@ ---- - -- name: "6.2.2.1.1 | PATCH | Ensure systemd-journal-remote is installed" - when: - - rhel9cis_rule_6_2_2_1_1 - - not rhel9cis_system_is_log_server - tags: - - level1-server - - level1-workstation - - patch - - journald - - rule_6.2.2.1.1 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-7 - - NIST800-53R5_AU-12 - ansible.builtin.package: - name: systemd-journal-remote - state: present - -- name: "6.2.2.1.2 | PATCH | Ensure systemd-journal-upload authentication is configured" - when: - - rhel9cis_rule_6_2_2_1_2 - - not rhel9cis_system_is_log_server - tags: - - level1-server - - level1-workstation - - patch - - journald - - rule_6.2.2.1.2 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-12 - notify: Restart journald - ansible.builtin.lineinfile: - path: /etc/systemd/journal-upload.conf - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - loop: - - { regexp: 'URL=', line: 'URL={{ rhel9cis_journal_upload_url }}'} - - { regexp: 'ServerKeyFile=', line: 'ServerKeyFile={{ rhel9cis_journal_upload_serverkeyfile }}'} - - { regexp: 'ServerCertificateFile=', line: 'ServerCertificateFile={{ rhel9cis_journal_servercertificatefile }}'} - - { regexp: 'TrustedCertificateFile=', line: 'TrustedCertificateFile={{ rhel9cis_journal_trustedcertificatefile }}'} - -- name: "6.2.2.1.3 | PATCH | Ensure systemd-journal-upload is enabled and active" - when: - - not rhel9cis_system_is_log_server - - rhel9cis_rule_6_2_2_1_3 - tags: - - level1-server - - level1-workstation - - patch - - journald - - rule_6.2.2.1.3 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-12 - ansible.builtin.systemd: - name: systemd-journal-upload - masked: false - enabled: true - -- name: "6.2.2.1.4 | PATCH | Ensure systemd-journal-remote service is not in use" - when: - - not rhel9cis_system_is_log_server - - rhel9cis_rule_6_2_2_1_4 - tags: - - level1-server - - level1-workstation - - patch - - journald - - rule_6.2.2.1.4 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-7 - - NIST800-53R5_AU-12 - ansible.builtin.systemd: - name: "{{ item }}" - state: stopped - enabled: false - masked: true - loop: - - systemd-journal-remote.socket - - systemd-journal-remote.service diff --git a/tasks/section_6/cis_6.2.2.x.yml b/tasks/section_6/cis_6.2.2.x.yml deleted file mode 100644 index fe0f8c4..0000000 --- a/tasks/section_6/cis_6.2.2.x.yml +++ /dev/null @@ -1,80 +0,0 @@ ---- - -- name: "6.2.2.2 | PATCH | Ensure journald ForwardToSyslog is disabled" - when: rhel9cis_rule_6_2_2_2 - tags: - - level1-server - - level2-workstation - - patch - - journald - - rule_6.2.2.2 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-6 - - NIST800-53R5_AU-7 - - NIST800-53R5_AU-12 - notify: Restart journald - block: - - name: "6.2.2.2 | PATCH | Ensure journald ForwardToSyslog is disabled | Add file" - ansible.builtin.template: - src: etc/systemd/journald.conf.d/forwardtosyslog.conf.j2 - dest: /etc/systemd/journald.conf.d/forwardtosyslog.conf - owner: root - group: root - mode: 'g-wx,o-rwx' - - - name: "6.2.2.2 | PATCH | Ensure journald ForwardToSyslog is disabled | comment out current entries" - ansible.builtin.replace: - path: /etc/systemd/journald.conf - regexp: ^(\s*ForwardToSyslog) - replace: '#\1' - -- name: "6.2.2.3 | PATCH | Ensure journald Compress is configured" - when: rhel9cis_rule_6_2_2_3 - tags: - - level1-server - - level1-workstation - - patch - - journald - - rule_6.2.2.3 - - NIST800-53R5_AU-4 - notify: Restart journald - block: - - name: "6.2.2.3 | PATCH | Ensure journald Compress is configured | Add file" - ansible.builtin.template: - src: etc/systemd/journald.conf.d/storage.conf.j2 # Added to the same file as 6.2.1.1.4 - dest: /etc/systemd/journald.conf.d/storage.conf - owner: root - group: root - mode: 'g-wx,o-rwx' - - - name: "6.2.2.3 | PATCH | Ensure journald Compress is configured | comment out current entries" - ansible.builtin.replace: - path: /etc/systemd/journald.conf - regexp: (?i)(\s*compress=) - replace: '#\1' - -- name: "6.2.2.4 | PATCH | Ensure journald Storage is configured" - when: rhel9cis_rule_6_2_2_4 - tags: - - level1-server - - level1-workstation - - patch - - journald - - rule_6.2.2.4 - - NIST800-53R5_AU-3 - - NIST800-53R5_AU-12 - notify: Restart journald - block: - - name: "6.2.2.4 | PATCH | Ensure journald Storage is configured | Add file" - ansible.builtin.template: - src: etc/systemd/journald.conf.d/storage.conf.j2 - dest: /etc/systemd/journald.conf.d/storage.conf - owner: root - group: root - mode: 'g-wx,o-rwx' - - - name: "6.2.2.4 | PATCH | Ensure journald Storage is configured | comment out current entries" - ansible.builtin.replace: - path: /etc/systemd/journald.conf - regexp: (?i)(\s*storage=) - replace: '#\1' diff --git a/tasks/section_6/cis_6.2.3.x.yml b/tasks/section_6/cis_6.2.3.x.yml deleted file mode 100644 index eaa3bd1..0000000 --- a/tasks/section_6/cis_6.2.3.x.yml +++ /dev/null @@ -1,263 +0,0 @@ ---- - -- name: "6.2.3.1 | PATCH | Ensure rsyslog installed" - when: - - "'rsyslog' not in ansible_facts.packages" - - rhel9cis_rule_6_2_3_1 - tags: - - level1-server - - level1-workstation - - patch - - rsyslog - - rule_6.2.3.1 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-3 - - NIST800-53R5_AU-12 - ansible.builtin.package: - name: rsyslog - state: present - -- name: "6.2.3.2 | PATCH | Ensure rsyslog Service is enabled and active" - when: rhel9cis_rule_6_2_3_2 - tags: - - level1-server - - level1-workstation - - patch - - rsyslog - - rule_6.2.3.2 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-3 - - NIST800-53R5_AU-12 - ansible.builtin.systemd: - name: rsyslog - enabled: true - state: started - -- name: "6.2.3.3 | PATCH | Ensure journald is configured to send logs to rsyslog" - when: rhel9cis_rule_6_2_3_3 - tags: - - level1-server - - level1-workstation - - patch - - rule_6.2.3.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-4 - - NIST800-53R5_AU-12 - - NIST800-53R5_MP-2 - ansible.builtin.lineinfile: - path: /etc/systemd/journald.conf - regexp: "^#ForwardToSyslog=|^ForwardToSyslog=" - line: ForwardToSyslog=yes - notify: Restart rsyslog - -- name: "6.2.3.4 | PATCH | Ensure rsyslog log file creation mode is configured" - when: rhel9cis_rule_6_2_3_4 - tags: - - level1-server - - level1-workstation - - patch - - rsyslog - - rule_6.2.3.4 - - NIST800-53R5_AC-3 - - NIST800-53R5_AC-6 - - NIST800-53R5_MP-2 - ansible.builtin.lineinfile: - path: /etc/rsyslog.conf - regexp: '^\$FileCreateMode' - line: '$FileCreateMode 0640' - notify: Restart rsyslog - -- name: "6.2.3.5 | PATCH | Ensure logging is configured" - when: rhel9cis_rule_6_2_3_5 - tags: - - level1-server - - level1-workstation - - patch - - rsyslog - - rule_6.2.3.5 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-7 - - NIST800-53R5_AU-12 - block: - - name: "6.2.3.5 | AUDIT | Ensure logging is configured | rsyslog current config message out" - ansible.builtin.shell: cat /etc/rsyslog.conf | grep -Ev "^#|^$" - changed_when: false - failed_when: false - check_mode: false - register: discovered_configured_rsyslog - - - name: "6.2.3.5 | AUDIT | Ensure logging is configured | rsyslog current config message out" - ansible.builtin.debug: - msg: - - "These are the current logging configurations for rsyslog, please review:" - - "{{ discovered_configured_rsyslog.stdout_lines }}" - - - name: "6.2.3.5 | PATCH | Ensure logging is configured | mail.* log setting" - when: rhel9cis_rsyslog_ansiblemanaged - ansible.builtin.blockinfile: - path: /etc/rsyslog.conf - marker: "# {mark} MAIL LOG SETTINGS - CIS benchmark - Ansible-lockdown" - block: | - # mail logging additions to meet CIS standards - mail.* -/var/log/mail - mail.info -/var/log/mail.info - mail.warning -/var/log/mail.warning - mail.err /var/log/mail.err - insertafter: '# Log all the mail messages in one place.' - notify: Restart rsyslog - - - name: "6.2.3.5 | PATCH | Ensure logging is configured | news.crit log setting" - when: rhel9cis_rsyslog_ansiblemanaged - ansible.builtin.blockinfile: - path: /etc/rsyslog.conf - state: present - marker: "# {mark} NEWS LOG SETTINGS - CIS benchmark - Ansible-lockdown" - block: | - # news logging additions to meet CIS standards - news.crit -/var/log/news/news.crit - news.notice -/var/log/news/news.crit - insertafter: '# Save news errors of level crit and higher in a special file.' - notify: Restart rsyslog - - - name: "6.2.3.5 | PATCH | Ensure logging is configured | Misc. log setting" - when: rhel9cis_rsyslog_ansiblemanaged - ansible.builtin.blockinfile: - path: /etc/rsyslog.conf - state: present - marker: "# {mark} MISC. LOG SETTINGS - CIS benchmark - Ansible-lockdown" - block: | - # misc. logging additions to meet CIS standards - *.=warning;*.=err -/var/log/warn - *.crit /var/log/warn - *.*;mail.none;news.none /var/log/messages - insertbefore: '# ### sample forwarding rule ###' - notify: Restart rsyslog - - - name: "6.2.3.5 | PATCH | Ensure logging is configured | Local log settings" - ansible.builtin.blockinfile: - path: /etc/rsyslog.conf - state: present - marker: "#{mark} LOCAL LOG SETTINGS - CIS benchmark - Ansible-lockdown" - block: | - # local log settings to meet CIS standards - local0,local1.* -/var/log/localmessages - local2,local3.* -/var/log/localmessages - local4,local5.* -/var/log/localmessages - local6,local7.* -/var/log/localmessages - *.emerg :omusrmsg:* - insertafter: '#### RULES ####' - notify: Restart rsyslog - - - name: "6.2.3.5 | PATCH | Ensure logging is configured | Auth Settings" - ansible.builtin.blockinfile: - path: /etc/rsyslog.conf - state: present - marker: "#{mark} Auth SETTINGS - CIS benchmark - Ansible-lockdown" - block: | - # Private settings to meet CIS standards - auth,authpriv.* /var/log/secure - insertafter: '#### RULES ####' - notify: Restart rsyslog - - - name: "6.2.3.5 | PATCH | Ensure logging is configured | Cron Settings" - ansible.builtin.blockinfile: - path: /etc/rsyslog.conf - state: present - marker: "#{mark} Cron SETTINGS - CIS benchmark - Ansible-lockdown" - block: | - # Cron settings to meet CIS standards - cron.* /var/log/cron - insertafter: '#### RULES ####' - notify: Restart rsyslog - -- name: "6.2.3.6 | PATCH | Ensure rsyslog is configured to send logs to a remote log host" - when: - - rhel9cis_rule_6_2_3_6 - - rhel9cis_remote_log_server - tags: - - level1-server - - level1-workstation - - patch - - rsyslog - - rule_6.2.3.6 - - NIST800-53R5_AU-6 - ansible.builtin.blockinfile: - path: /etc/rsyslog.conf - state: present - block: | - # target can be IP or FQDN - *.* action(type="omfwd" target="{{ rhel9cis_remote_log_host }}" port="{{ rhel9cis_remote_log_port }}" protocol="{{ rhel9cis_remote_log_protocol }}" action.resumeRetryCount="{{ rhel9cis_remote_log_retrycount }}" queue.type="LinkedList" queue.size="{{ rhel9cis_remote_log_queuesize }}") - insertafter: EOF - failed_when: - - discovered_rsyslog_remote_host is failed - - discovered_rsyslog_remote_host.rc != 257 - register: discovered_rsyslog_remote_host - notify: Restart rsyslog - -- name: "6.2.3.7 | PATCH | Ensure rsyslog is not configured to recieve logs from a remote client" - when: rhel9cis_rule_6_2_3_7 - tags: - - level1-server - - level1-workstation - - patch - - rsyslog - - rule_6.2.3.7 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-7 - - NIST800-53R5_AU-12 - - NIST800-53R5_CM-6 - block: - - name: "6.2.3.7 | PATCH | Ensure rsyslog is not configured to recieve logs from a remote client. | When not log host" - when: not rhel9cis_system_is_log_server - ansible.builtin.replace: - path: /etc/rsyslog.conf - regexp: '{{ item }}' - replace: '#\1' - notify: Restart rsyslog - loop: - - '^(\$ModLoad imtcp)' - - '^(\$InputTCPServerRun)' - - '^(module\(load="imtcp"\))' - - '^(input\(type="imtcp")' - - - name: "6.2.3.7 | PATCH | Ensure rsyslog is not configured to recieve logs from a remote clients. | When log host" - when: rhel9cis_system_is_log_server - ansible.builtin.replace: - path: /etc/rsyslog.conf - regexp: '^#(.*{{ item }}.*)' - replace: '\1' - notify: Restart rsyslog - loop: - - 'ModLoad imtcp' - - 'InputTCPServerRun' - -- name: "6.2.3.8 | PATCH | Ensure rsyslog logrotate is configured" - when: rhel9cis_rule_6_2_3_8 - tags: - - level1-server - - level1-workstation - - manual - - patch - - logrotate - - rule_6.2.3.8 - - NIST800-53R5_AU-8 - block: - - name: "6.2.3.8 | PATCH | Ensure rsyslog logrotate is configured | installed" - ansible.builtin.package: - name: rsyslog-logrotate - state: present - - - name: "6.2.3.8 | PATCH | Ensure rsyslog logrotate is configured | scheduled" - ansible.builtin.systemd: - name: logrotate.timer - state: started - enabled: true - - - name: "6.2.3.8 | PATCH | Ensure logrotate is configured | set rsyslog conf" - ansible.builtin.template: - src: etc/logrotate.d/rsyslog_log.j2 - dest: /etc/logrotate.d/rsyslog_log - owner: root - group: root - mode: 'g-wx,o-rwx' diff --git a/tasks/section_6/cis_6.2.4.1.yml b/tasks/section_6/cis_6.2.4.1.yml deleted file mode 100644 index 9e8b9b3..0000000 --- a/tasks/section_6/cis_6.2.4.1.yml +++ /dev/null @@ -1,51 +0,0 @@ ---- - -- name: "6.2.4.1 | PATCH | Ensure access to all logfiles has been configured" - when: rhel9cis_rule_6_2_4_1 - tags: - - level1-server - - level1-workstation - - patch - - logfiles - - rule_6.2.4.1 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - block: - - name: "6.2.4.1 | AUDIT | Ensure access to all logfiles has been configured | find log files" - ansible.builtin.shell: find /var/log/ -type f -exec ls {} \; - changed_when: false - failed_when: false - register: discovered_logfiles - - - name: "6.2.4.1 | PATCH | Ensure access to all logfiles has been configured | change permissions SSSD min 660" - when: - - discovered_logfiles.stdout_lines | length > 0 - - item is match("/var/log/(gdm|sssd)") - ansible.builtin.file: - path: "{{ item }}" - mode: 'ug-x,o-rwx' - failed_when: discovered_logfile_list.state not in '[ file, absent ]' - register: discovered_logfile_list - loop: "{{ discovered_logfiles.stdout_lines }}" - - - name: "6.2.4.1 | PATCH | Ensure access to all logfiles has been configured | change permissions tmp min 664" - when: - - discovered_logfiles.stdout_lines | length > 0 - - item is match("/var/log/((u|b|w)tmp*|lastlog)") - ansible.builtin.file: - path: "{{ item }}" - mode: 'ug-x,o-wx' - failed_when: discovered_logfile_list.state not in '[ file, absent ]' - register: discovered_logfile_list - loop: "{{ discovered_logfiles.stdout_lines }}" - - - name: "6.2.4.1 | PATCH | Ensure access to all logfiles has been configured | change permissions else all 640" - when: - - discovered_logfiles.stdout_lines | length > 0 - - item is not match("/var/log/((u|b|w)tmp*|lastlog|sssd)") - ansible.builtin.file: - path: "{{ item }}" - mode: 'u-x,g-wx,o-rwx' - failed_when: discovered_logfile_list.state not in '[ file, absent ]' - register: discovered_logfile_list - loop: "{{ discovered_logfiles.stdout_lines }}" diff --git a/tasks/section_6/cis_6.2.x.yml b/tasks/section_6/cis_6.2.x.yml new file mode 100644 index 0000000..618cadb --- /dev/null +++ b/tasks/section_6/cis_6.2.x.yml @@ -0,0 +1,452 @@ +--- + +- name: "6.2.1 | AUDIT | Ensure accounts in /etc/passwd use shadowed passwords" + block: + - name: "6.2.1 | AUDIT | Ensure accounts in /etc/passwd use shadowed passwords | discover" + ansible.builtin.shell: awk -F':' '($2 != "x" ) { print $1 " is not set to shadowed passwords "}' /etc/passwd + changed_when: false + register: shadow_passwd + + - name: "6.2.1 | AUDIT | Ensure accounts in /etc/passwd use shadowed passwords | Output" + ansible.builtin.debug: + msg: | + - "Warning!! Below are the accounts that do not have shadowed passwords set" + - "{{ shadow_passwd.stdout_line }}" + when: shadow_passwd.stdout | length > 0 + + - name: "6.2.1 | AUDIT | Ensure accounts in /etc/passwd use shadowed passwords | warning fact" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '6.2.1' + when: shadow_passwd.stdout | length >= 1 + + when: + - rhel9cis_rule_6_2_1 + tags: + - level1-server + - level1-workstation + - patch + - accounts + - rule_6.2.1 + +- name: "6.2.2 | PATCH | Ensure password fields are not empty" + ansible.builtin.shell: passwd -l {{ item }} + changed_when: false + failed_when: false + loop: "{{ empty_password_accounts.stdout_lines }}" + when: + - empty_password_accounts.rc + - rhel9cis_rule_6_2_2 + tags: + - level1-server + - level1-workstation + - patch + - accounts + - rule_6.2.2 + +- name: "6.2.3 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group" + block: + - name: "6.2.3 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group | Check /etc/passwd entries" + ansible.builtin.shell: pwck -r | grep 'no group' | awk '{ gsub("[:\47]",""); print $2}' + changed_when: false + failed_when: false + check_mode: false + register: rhel9cis_6_2_3_passwd_gid_check + + - name: "6.2.3 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group | Print warning about users with invalid GIDs missing GID entries in /etc/group" + ansible.builtin.debug: + msg: "Warning!! The following users have non-existent GIDs (Groups): {{ rhel9cis_6_2_3_passwd_gid_check.stdout_lines | join (', ') }}" + when: rhel9cis_6_2_3_passwd_gid_check.stdout | length >= 1 + + - name: "6.2.3 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group | warning count" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '6.2.3' + when: rhel9cis_6_2_3_passwd_gid_check.stdout | length >= 1 + when: + - rhel9cis_rule_6_2_3 + tags: + - level1-server + - level1-workstation + - audit + - accounts + - groups + - rule_6.2.2 + +- name: "6.2.4 | AUDIT Ensure no duplicate UIDs exist" + block: + - name: "6.2.4 | AUDIT | Ensure no duplicate UIDs exist | Check for duplicate UIDs" + ansible.builtin.shell: "pwck -r | awk -F: '{if ($3 in uid) print $1 ; else uid[$3]}' /etc/passwd" + changed_when: false + failed_when: false + register: rhel9cis_6_2_4_user_uid_check + + - name: "6.2.4 | AUDIT | Ensure no duplicate UIDs exist | Print warning about users with duplicate UIDs" + ansible.builtin.debug: + msg: "Warning!! The following users have UIDs that are duplicates: {{ rhel9cis_6_2_4_user_uid_check.stdout_lines }}" + when: rhel9cis_6_2_4_user_uid_check.stdout | length >= 1 + + - name: "6.2.4 | AUDIT| Ensure no duplicate UIDs exist | warning count" + ansible.builtin.import_tasks: warning_facts.yml + when: rhel9cis_6_2_4_user_uid_check.stdout | length >= 1 + vars: + warn_control_id: '6.2.4' + when: + - rhel9cis_rule_6_2_4 + tags: + - level1-server + - level1-workstation + - audit + - accounts + - users + - rule_6.2.4 + +- name: "6.2.5 | AUDIT | Ensure no duplicate GIDs exist" + block: + - name: "6.2.5 | AUDIT | Ensure no duplicate GIDs exist | Check for duplicate GIDs" + ansible.builtin.shell: "pwck -r | awk -F: '{if ($3 in users) print $1 ; else users[$3]}' /etc/group" + changed_when: false + failed_when: false + register: rhel9cis_6_2_5_user_user_check + + - name: "6.2.5 | AUDIT | Ensure no duplicate GIDs exist | Print warning about users with duplicate GIDs" + ansible.builtin.debug: + msg: "Warning!! The following groups have duplicate GIDs: {{ rhel9cis_6_2_5_user_user_check.stdout_lines }}" + when: rhel9cis_6_2_5_user_user_check.stdout | length >= 1 + + - name: "6.2.5 | AUDIT | Ensure no duplicate GIDs exist | warning count" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '6.2.5' + when: rhel9cis_6_2_5_user_user_check.stdout_lines | length >= 1 + + when: + - rhel9cis_rule_6_2_5 + tags: + - level1-server + - level1-workstation + - audit + - accounts + - groups + - rule_6.2.5 + +- name: "6.2.6 | AUDIT | Ensure no duplicate user names exist" + block: + - name: "6.2.6 | AUDIT | Ensure no duplicate user names exist | Check for duplicate User Names" + ansible.builtin.shell: "pwck -r | awk -F: '{if ($1 in users) print $1 ; else users[$1]}' /etc/passwd" + changed_when: false + failed_when: false + register: rhel9cis_6_2_6_user_username_check + + - name: "6.2.6 | AUDIT | Ensure no duplicate user names exist | Print warning about users with duplicate User Names" + ansible.builtin.debug: + msg: "Warning!! The following user names are duplicates: {{ rhel9cis_6_2_6_user_username_check.stdout_lines }}" + when: rhel9cis_6_2_6_user_username_check.stdout | length >= 1 + + - name: "6.2.6 | AUDIT | Ensure no duplicate user names exist | warning count" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '6.2.6' + when: rhel9cis_6_2_6_user_username_check.stdout | length >= 1 + when: + - rhel9cis_rule_6_2_6 + tags: + - level1-server + - level1-workstation + - audit + - accounts + - users + - rule_6.2.6 + +- name: "6.2.7 | AUDIT | Ensure no duplicate group names exist" + block: + - name: "6.2.7 | AUDIT | Ensure no duplicate group names exist | Check for duplicate group names" + ansible.builtin.shell: 'getent passwd | cut -d: -f1 | sort -n | uniq -d' + changed_when: false + failed_when: false + check_mode: false + register: rhel9cis_6_2_7_group_group_check + + - name: "6.2.7 | AUDIT | Ensure no duplicate group names exist | Print warning about users with duplicate group names" + ansible.builtin.debug: + msg: "Warning!! The following group names are duplicates: {{ rhel9cis_6_2_7_group_group_check.stdout_lines }}" + when: rhel9cis_6_2_7_group_group_check.stdout is not defined + + - name: "6.2.7 | AUDIT | Ensure no duplicate group names exist | warning count" + ansible.builtin.import_tasks: warning_facts.yml + vars: + warn_control_id: '6.2.7' + when: rhel9cis_6_2_7_group_group_check.stdout is not defined + when: + - rhel9cis_rule_6_2_7 + tags: + - level1-server + - level1-workstation + - audit + - accounts + - groups + - rule_6.2.7 + +- name: "6.2.8 | PATCH | Ensure root PATH Integrity" + block: + - name: "6.2.8 | AUDIT | Ensure root PATH Integrity | Get root paths" + ansible.builtin.shell: sudo -Hiu root env | grep '^PATH' | cut -d= -f2 + changed_when: false + register: rhel9cis_6_2_8_root_paths + + - name: "6.2.8 | AUDIT | Ensure root PATH Integrity | Get root paths" + ansible.builtin.shell: sudo -Hiu root env | grep '^PATH' | cut -d= -f2 | tr ":" "\n" + changed_when: false + register: rhel9cis_6_2_8_root_paths_split + + - name: "6.2.8 | AUDIT | Ensure root PATH Integrity | Set fact" + ansible.builtin.set_fact: + root_paths: "{{ rhel9cis_6_2_8_root_paths.stdout }}" + + - name: "6.2.8 | AUDIT | Ensure root PATH Integrity | Check for empty dirs" + ansible.builtin.shell: 'echo {{ root_paths }} | grep -q "::" && echo "roots path contains a empty directory (::)"' + changed_when: false + failed_when: root_path_empty_dir.rc not in [ 0, 1 ] + register: root_path_empty_dir + + - name: "6.2.8 | AUDIT | Ensure root PATH Integrity | Check for trailing ':'" + ansible.builtin.shell: '{{ root_paths }} | cut -d= -f2 | grep -q ":$" && echo "roots path contains a trailing (:)"' + changed_when: false + failed_when: root_path_trailing_colon.rc not in [ 0, 1 ] + register: root_path_trailing_colon + + - name: "6.2.8 | AUDIT | Ensure root PATH Integrity | Check for owner and permissions" + block: + - name: "6.2.8 | AUDIT | Ensure root PATH Integrity | Check for owner and permissions" + ansible.builtin.stat: + path: "{{ item }}" + register: root_path_perms + loop: "{{ rhel9cis_6_2_8_root_paths_split.stdout_lines }}" + + - name: "6.2.8 | AUDIT | Ensure root PATH Integrity | Set permissions" + ansible.builtin.file: + path: "{{ item.stat.path }}" + state: directory + owner: root + group: root + mode: "0755" + follow: false + loop: "{{ root_path_perms.results }}" + loop_control: + label: "{{ item }}" + when: + - item.stat.exists + - item.stat.isdir + - item.stat.pw_name != 'root' or item.stat.gr_name != 'root' or item.stat.woth or item.stat.wgrp + when: + - rhel9cis_rule_6_2_8 + tags: + - level1-server + - level1-workstation + - patch + - paths + - rule_6.2.8 + +- name: "6.2.9 | PATCH | Ensure root is the only UID 0 account" + ansible.builtin.shell: passwd -l {{ item }} + changed_when: false + failed_when: false + loop: "{{ rhel9cis_uid_zero_accounts_except_root.stdout_lines }}" + when: + - rhel9cis_uid_zero_accounts_except_root.rc + - rhel9cis_rule_6_2_9 + tags: + - level1-server + - level1-workstation + - patch + - accounts + - users + - rule_6.2.9 + +- name: "6.2.10 | PATCH | Ensure local interactive user home directories exist" + block: + - name: "6.2.10 | PATCH | Ensure local interactive user home directories exist | Create dir if absent" + ansible.builtin.file: + path: "{{ item.dir }}" + state: directory + owner: "{{ item.id }}" + group: "{{ item.gid }}" + register: rhel_09_6_2_10_home_dir + loop: "{{ rhel9cis_passwd | selectattr('uid', '>=', min_int_uid | int ) | selectattr('uid', '<=', max_int_uid | int ) | list }}" + loop_control: + label: "{{ item.id }}" + + # set default ACLs so the homedir has an effective umask of 0027 + - name: "6.2.10 | PATCH | Ensure local interactive user home directories exist | Set group ACL" + ansible.posix.acl: + path: "{{ item }}" + default: true + etype: group + permissions: rx + state: present + loop: "{{ interactive_users_home.stdout_lines }}" + when: not system_is_container + + - name: "6.2.10 | PATCH | Ensure local interactive user home directories exist | Set other ACL" + ansible.posix.acl: + path: "{{ item }}" + default: true + etype: other + permissions: 0 + state: present + loop: "{{ interactive_users_home.stdout_lines }}" + when: not system_is_container + when: + - rhel9cis_rule_6_2_10 + tags: + - level1-server + - level1-workstation + - patch + - users + - rule_6.2.10 + +- name: "6.2.11 | PATCH | Ensure local interactive users own their home directories" + ansible.builtin.file: + path: "{{ item.dir }}" + owner: "{{ item.id }}" + state: directory + loop: "{{ rhel9cis_passwd | selectattr('uid', '>=', min_int_uid | int ) | selectattr('uid', '<=', max_int_uid | int ) | list }}" + loop_control: + label: "{{ item.id }}" + when: + - item.uid >= min_int_uid | int + - item.id != 'nobody' + - (item.id != 'tss' and item.dir != '/dev/null') + - item.shell != '/sbin/nologin' + - rhel9cis_rule_6_2_11 + tags: + - level1-server + - level1-workstation + - patch + - users + - rule_6.2.11 + +- name: "6.2.12 | PATCH | Ensure local interactive user home directories are mode 750 or more restrictive" + block: + - name: "6.2.12 | AUDIT | Ensure local interactive user home directories are mode 750 or more restrictive | get stat" + ansible.builtin.stat: + path: "{{ item }}" + register: rhel_09_6_2_12_home_dir_perms + loop: "{{ interactive_users_home.stdout_lines }}" + + - name: "6.2.12 | PATCH | Ensure local interactive user home directories are mode 750 or more restrictive | amend if needed" + ansible.builtin.file: + path: "{{ item.stat.path }}" + state: directory + mode: "0750" + loop: "{{ rhel_09_6_2_12_home_dir_perms.results }}" + loop_control: + label: "{{ item }}" + when: + - item.stat.mode > '0750' + + # set default ACLs so the homedir has an effective umask of 0027 + - name: "6.2.12 | PATCH | Ensure local interactive user home directories are mode 750 or more restrictive | Set group ACL" + ansible.posix.acl: + path: "{{ item }}" + default: true + etype: group + permissions: rx + state: present + loop: "{{ interactive_users_home.stdout_lines }}" + when: not system_is_container + + - name: "6.2.12 | PATCH | Ensure local interactive user home directories are mode 750 or more restrictive | Set other ACL" + ansible.posix.acl: + path: "{{ item }}" + default: true + etype: other + permissions: 0 + state: present + loop: "{{ interactive_users_home.stdout_lines }}" + when: not system_is_container + when: + - rhel9cis_rule_6_2_12 + tags: + - level1-server + - level1-workstation + - patch + - users + - permissions + - rule_6.2.12 + +- name: "6.2.13 | PATCH | Ensure no local interactive user has .netrc files" + ansible.builtin.file: + path: "{{ item }}/.netrc" + state: absent + loop: "{{ interactive_users_home.stdout_lines }}" + when: + - rhel9cis_rule_6_2_13 + tags: + - level1-server + - level1-workstation + - patch + - users + - permissions + - rule_6.2.13 + +- name: "6.2.14 | PATCH | Ensure no local interactive user has .forward files" + ansible.builtin.file: + path: "{{ item }}/.forward" + state: absent + loop: "{{ interactive_users_home.stdout_lines }}" + when: + - rhel9cis_rule_6_2_14 + tags: + - level1-server + - level1-workstation + - patch + - users + - files + - rule_6.2.14 + +- name: "6.2.15 | PATCH | Ensure no local interactive user has .rhosts files" + ansible.builtin.file: + path: "~{{ item }}/.rhosts" + state: absent + loop: "{{ interactive_users_home.stdout_lines }}" + when: + - rhel9cis_rule_6_2_15 + tags: + - level1-server + - level1-workstation + - patch + - users + - files + - rule_6.2.15 + +- name: "6.2.16 | PATCH | Ensure local interactive user dot files are not group or world writable" + block: + - name: "6.2.16 | AUDIT | Ensure local interactive user dot files are not group or world writable | Check for files" + ansible.builtin.find: + path: /home + depth: 3 + patterns: ".*" + hidden: true + recurse: true + file_type: file + register: user_dot_files + + - name: "6.2.16 | AUDIT | Ensure local interactive user dot files are not group or world writable | update permissions" + ansible.builtin.file: + path: "{{ item.path }}" + mode: go-w + follow: "{{ rhel_09_6_2_16_home_follow_symlinks }}" + loop: "{{ user_dot_files.files }}" + loop_control: + label: "{{ item.path }}" + + when: + - rhel9cis_rule_6_2_16 + tags: + - level1-server + - level1-workstation + - patch + - users + - permissions + - rule_6.2.16 diff --git a/tasks/section_6/cis_6.3.1.x.yml b/tasks/section_6/cis_6.3.1.x.yml deleted file mode 100644 index e795c83..0000000 --- a/tasks/section_6/cis_6.3.1.x.yml +++ /dev/null @@ -1,107 +0,0 @@ ---- - -- name: "6.3.1.1 | PATCH | Ensure auditd is installed" - when: rhel9cis_rule_6_3_1_1 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.1.1 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-3 - - NIST800-53R5_AU-12 - - NIST800-53R5_SI-5 - block: - - name: "6.3.1.1 | PATCH | Ensure auditd is installed | Install auditd packages" - when: '"auditd" not in ansible_facts.packages' - ansible.builtin.package: - name: audit - state: present - - - name: "6.3.1.1 | PATCH | Ensure auditd is installed | Install auditd-lib packages" - when: '"auditd-lib" not in ansible_facts.packages' - ansible.builtin.package: - name: audit-libs - state: present - -- name: "6.3.1.2 | PATCH | Ensure auditing for processes that start prior to auditd is enabled" - when: rhel9cis_rule_6_3_1_2 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - grub - - rule_6.3.1.2 - block: - - name: "6.3.1.2 | PATCH | Ensure auditing for processes that start prior to auditd is enabled | Grubby existence of current value" - ansible.builtin.shell: grubby --info=ALL | grep args | sed -n 's/.*audit=\([[:alnum:]]\+\).*/\1/p' - changed_when: false - failed_when: false - check_mode: false - register: discovered_grubby_curr_value_audit_linux - - - name: "6.3.1.2 | PATCH | Ensure auditing for processes that start prior to auditd is enabled | Grubby update, if needed" - when: - - discovered_grubby_curr_value_audit_linux.stdout == '' or - '0' in discovered_grubby_curr_value_audit_linux.stdout or - 'off' in discovered_grubby_curr_value_audit_linux.stdout|lower - ansible.builtin.command: grubby --update-kernel=ALL --args="audit=1" - changed_when: true - -- name: "6.3.1.3 | PATCH | Ensure audit_backlog_limit is sufficient" - when: rhel9cis_rule_6_3_1_3 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - grub - - rule_6.3.1.3 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-12 - - NIST800-53R5_SI-5 - block: - - name: "6.3.1.3 | AUDIT | Ensure audit_backlog_limit is sufficient | Grubby existence of current value" - ansible.builtin.shell: - cmd: 'grubby --info=ALL | grep args | grep -o -E "audit_backlog_limit=([[:digit:]])+" | grep -o -E "([[:digit:]])+"' - changed_when: false - failed_when: false - check_mode: false - register: discovered_grubby_curr_value_backlog_linux - - - name: "6.3.1.3 | AUDIT | Check to see if limits are set" - when: - - discovered_grubby_curr_value_backlog_linux is not defined or - discovered_grubby_curr_value_backlog_linux.stdout_lines == [] - ansible.builtin.set_fact: - discovered_reset_backlog_limits: true - - - name: "6.3.1.3 | AUDIT | Check to see if any limits are too low" - when: (item | int < rhel9cis_audit_back_log_limit) - ansible.builtin.set_fact: - discovered_reset_backlog_limits: true - loop: "{{ discovered_grubby_curr_value_backlog_linux.stdout_lines }}" - - - name: "6.3.1.3 | AUDIT | Ensure audit_backlog_limit is sufficient | Grubby update applied" - when: discovered_reset_backlog_limits is defined - ansible.builtin.command: - cmd: 'grubby --update-kernel=ALL --args="audit_backlog_limit={{ rhel9cis_audit_back_log_limit }}"' - changed_when: true - -- name: "6.3.1.4 | PATCH | Ensure auditd service is enabled and active" - when: rhel9cis_rule_6_3_1_4 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.1.4 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-12 - - NIST800-53R5_SI-5 - ansible.builtin.systemd: - name: auditd - state: started - enabled: true diff --git a/tasks/section_6/cis_6.3.2.x.yml b/tasks/section_6/cis_6.3.2.x.yml deleted file mode 100644 index dc0804f..0000000 --- a/tasks/section_6/cis_6.3.2.x.yml +++ /dev/null @@ -1,93 +0,0 @@ ---- - -- name: "6.3.2.1 | PATCH | Ensure audit log storage size is configured" - when: rhel9cis_rule_6_3_2_1 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.2.1 - - NIST800-53R5_AU-8 - ansible.builtin.lineinfile: - path: /etc/audit/auditd.conf - regexp: "^max_log_file( |=)" - line: "max_log_file = {{ rhel9cis_auditd_max_log_file_size }}" - notify: Restart auditd - -- name: "6.3.2.2 | PATCH | Ensure audit logs are not automatically deleted" - when: rhel9cis_rule_6_3_2_2 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.2.2 - - NIST800-53R5_AU-8 - ansible.builtin.lineinfile: - path: /etc/audit/auditd.conf - regexp: "^max_log_file_action" - line: "max_log_file_action = {{ rhel9cis_auditd_max_log_file_action }}" - notify: Restart auditd - -- name: "6.3.2.3 | PATCH | Ensure system is disabled when audit logs are full" - when: rhel9cis_rule_6_3_2_3 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.2.3 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-8 - - NIST800-53R5_AU-12 - - NIST800-53R5_SI-5 - ansible.builtin.lineinfile: - path: /etc/audit/auditd.conf - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - notify: Restart auditd - loop: - - { regexp: '^disk_full_action', line: 'disk_full_action = {{ rhel9cis_auditd_disk_full_action }}' } - - { regexp: '^disk_error_action', line: 'disk_error_action = {{ rhel9cis_auditd_disk_error_action }}' } - -- name: "6.3.2.4 | PATCH | Ensure system warns when audit logs are low on space" - when: rhel9cis_rule_6_3_2_4 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.2.4 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-8 - - NIST800-53R5_AU-12 - - NIST800-53R5_SI-5 - ansible.builtin.lineinfile: - path: /etc/audit/auditd.conf - regexp: "{{ item.regexp }}" - line: "{{ item.line }}" - notify: Restart auditd - loop: - - { regexp: '^space_left_action', line: 'space_left_action = {{ rhel9cis_auditd_space_left_action }}' } - - { regexp: '^admin_space_left_action', line: 'admin_space_left_action = {{ rhel9cis_auditd_admin_space_left_action }}' } - -- name: "PATCH | Configure other keys for auditd.conf" - when: - - rhel9cis_auditd_extra_conf.keys() | length > 0 - - rhel9cis_auditd_extra_conf_usage - tags: - - level2-server - - level2-workstation - - patch - - auditd - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-8 - - NIST800-53R5_AU-12 - - NIST800-53R5_SI-5 - ansible.builtin.lineinfile: - path: /etc/audit/auditd.conf - regexp: "^{{ item }}( |=)" - line: "{{ item }} = {{ rhel9cis_auditd_extra_conf[item] }}" - loop: "{{ rhel9cis_auditd_extra_conf.keys() }}" - notify: Restart auditd diff --git a/tasks/section_6/cis_6.3.3.x.yml b/tasks/section_6/cis_6.3.3.x.yml deleted file mode 100644 index 5ff73f9..0000000 --- a/tasks/section_6/cis_6.3.3.x.yml +++ /dev/null @@ -1,306 +0,0 @@ ---- - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.1 | PATCH | Ensure changes to system administration scope (sudoers) is collected" - when: rhel9cis_rule_6_3_3_1 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.1 - - NIST800-53R5_AU-3 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.2 | PATCH | Ensure actions as another user are always logged" - when: rhel9cis_rule_6_3_3_2 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.2 - - NIST800-53R5_AU-3 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.3 | PATCH | Ensure events that modify the sudo log file are collected" - when: rhel9cis_rule_6_3_3_3 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.3 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.4 | PATCH | Ensure events that modify date and time information are collected" - when: rhel9cis_rule_6_3_3_4 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.4 - - NIST800-53R5_AU-3 - - NIST800-53R5_CM-6 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.5 | PATCH | Ensure events that modify the system's network environment are collected" - when: rhel9cis_rule_6_3_3_5 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.5 - - NIST800-53R5_AU-3 - - NIST800-53R5_CM-6 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.6 | PATCH | Ensure use of privileged commands is collected" - when: rhel9cis_rule_6_3_3_6 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.6 - - NIST800-53R5_AU-3 - block: - - name: "6.3.3.6 | PATCH | Ensure use of privileged commands is collected" - ansible.builtin.shell: for i in $(df | grep '^/dev' | awk '{ print $NF }'); do find $i -xdev -type f -perm /6000 2>/dev/null; done - changed_when: false - failed_when: false - check_mode: false - register: discovered_priv_procs - - - name: "6.3.3.6 | PATCH | Ensure use of privileged commands is collected" - ansible.builtin.set_fact: - update_audit_template: true - notify: update auditd - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.7 | PATCH | Ensure unsuccessful file access attempts are collected" - when: rhel9cis_rule_6_3_3_7 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.7 - - NIST800-53R5_AU-3 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.8 | PATCH | Ensure events that modify user/group information are collected" - when: rhel9cis_rule_6_3_3_8 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.8 - - NIST800-53R5_AU-3 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.9 | PATCH | Ensure discretionary access control permission modification events are collected" - when: rhel9cis_rule_6_3_3_9 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.9 - - NIST800-53R5_AU-3 - - NIST800-53R5_CM-6 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.10 | PATCH | Ensure successful file system mounts are collected" - when: rhel9cis_rule_6_3_3_10 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.10 - - NIST800-53R5_CM-6 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.11 | PATCH | Ensure session initiation information is collected" - when: rhel9cis_rule_6_3_3_11 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.11 - - NIST800-53R5_AU-3 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.12 | PATCH | Ensure login and logout events are collected" - when: rhel9cis_rule_6_3_3_12 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.12 - - NIST800-53R5_AU-3 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.13 | PATCH | Ensure file deletion events by users are collected" - when: rhel9cis_rule_6_3_3_13 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.13 - - NIST800-53R5_AU-12 - - NIST800-53R5_SC-7 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.14 | PATCH | Ensure events that modify the system's Mandatory Access Controls are collected" - when: rhel9cis_rule_6_3_3_14 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.14 - - NIST800-53R5_AU-3 - - NIST800-53R5_CM-6 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.15 | PATCH | Ensure successful and unsuccessful attempts to use the chcon command are recorded" - when: rhel9cis_rule_6_3_3_15 - tags: - - level2-server - - level2- workstation - - patch - - auditd - - rule_6.3.3.15 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-12 - - NIST800-53R5_SI-5 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.16 | PATCH | Ensure successful and unsuccessful attempts to use the setfacl command are recorded" - when: rhel9cis_rule_6_3_3_16 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.16 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-12 - - NIST800-53R5_SI-5 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.17 | PATCH | Ensure successful and unsuccessful attempts to use the chacl command are recorded" - when: rhel9cis_rule_6_3_3_17 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.17 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-12 - - NIST800-53R5_SI-5 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.18 | PATCH | Ensure successful and unsuccessful attempts to use the usermod command are recorded" - when: rhel9cis_rule_6_3_3_18 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.18 - - NIST800-53R5_AU-2 - - NIST800-53R5_AU-12 - - NIST800-53R5_SI-5 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.19 | PATCH | Ensure kernel module loading and unloading and modification is collected" - when: rhel9cis_rule_6_3_3_19 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.19 - - NIST800-53R5_AU-3 - - NIST800-53R5_CM-6 - ansible.builtin.set_fact: - update_audit_template: true - -# All changes selected are managed by the POST audit and handlers to update -- name: "6.3.3.20 | PATCH | Ensure the audit configuration is immutable" - when: rhel9cis_rule_6_3_3_20 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.3.20 - - NIST800-53R5_AC-3 - - NIST800-53R5_AU-3 - - NIST800-53R5_MP-2 - ansible.builtin.set_fact: - update_audit_template: true - -- name: "6.3.3.21 | AUDIT | Ensure the running and on disk configuration is the same" - when: rhel9cis_rule_6_3_3_21 - tags: - - level2-server - - level2-workstation - - manual - - patch - - auditd - - rule_6.3.3.21 - - NIST800-53R5_AU-3 - ansible.builtin.debug: - msg: - - "Please run augenrules --load if you suspect there is a configuration that is not active" - -- name: Auditd | 6.3.3.x | Auditd controls updated - when: update_audit_template - ansible.builtin.debug: - msg: "Auditd Controls handled in POST using template - updating /etc/auditd/rules.d/99_auditd.rules" - changed_when: false diff --git a/tasks/section_6/cis_6.3.4.x.yml b/tasks/section_6/cis_6.3.4.x.yml deleted file mode 100644 index b044abc..0000000 --- a/tasks/section_6/cis_6.3.4.x.yml +++ /dev/null @@ -1,131 +0,0 @@ ---- - -- name: "6.3.4.1 | PATCH | Ensure the audit log file directory mode is configured" - when: rhel9cis_rule_6_3_4_1 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.4.1 - - NIST800-53R5_AU-3 - ansible.builtin.file: - path: "{{ prelim_auditd_logfile.stdout | dirname }}" - state: directory - mode: 'g-w,o-rwx' - -- name: | - "6.3.4.2 | PATCH | Ensure audit log files mode is configured" - "6.3.4.3 | PATCH | Ensure audit log files owner is configured" - "6.3.4.4 | PATCH | Ensure only authorized groups are assigned ownership of audit log files" - when: - - rhel9cis_rule_6_3_4_2 or - rhel9cis_rule_6_3_4_3 or - rhel9cis_rule_6_3_4_4 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.4.2 - - rule_6.3.4.3 - - rule_6.3.4.4 - - NIST800-53R5_AU-3 - ansible.builtin.file: - path: "{{ prelim_auditd_logfile.stdout }}" - mode: 'o-x,g-wx,o-rwx' - owner: root - group: root - -- name: "6.3.4.5 | PATCH | Ensure audit configuration files mode is configured" - when: rhel9cis_rule_6_3_4_5 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.4.5 - ansible.builtin.file: - path: "{{ item.path }}" - mode: 'u-x,g-wx,o-rwx' - failed_when: discovered_audit_conf_file_list.state not in '[ file, absent ]' - register: discovered_audit_conf_file_list - loop: "{{ prelim_auditd_conf_files.files }}" - loop_control: - label: "{{ item.path }}" - -- name: "6.3.4.6 | PATCH | Ensure audit configuration files owner is configured" - when: rhel9cis_rule_6_3_4_6 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.4.6 - ansible.builtin.file: - path: "{{ item.path }}" - owner: root - failed_when: discovered_audit_conf_file_list.state not in '[ file, absent ]' - register: discovered_audit_conf_file_list - loop: "{{ prelim_auditd_conf_files.files | default([]) }}" - loop_control: - label: "{{ item.path }}" - -- name: "6.3.4.7 | PATCH | Ensure audit configuration files group owner is configured" - when: rhel9cis_rule_6_3_4_7 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.4.7 - ansible.builtin.file: - path: "{{ item.path }}" - group: root - failed_when: discovered_audit_conf_file_list.state not in '[ file, absent ]' - register: discovered_audit_conf_file_list - loop: "{{ prelim_auditd_conf_files.files | default([]) }}" - loop_control: - label: "{{ item.path }}" - -- name: "6.3.4.8 | PATCH | Ensure audit tools mode is configured" - when: rhel9cis_rule_6_3_4_8 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.4.8 - - NIST800-53R5_AU-3 - ansible.builtin.file: - path: "{{ item }}" - mode: 'go-w' - loop: "{{ audit_bins }}" - -- name: "6.3.4.9 | PATCH | Ensure audit tools owner is configured" - when: rhel9cis_rule_6_3_4_9 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.4.9 - ansible.builtin.file: - path: "{{ item }}" - owner: root - group: root - loop: "{{ audit_bins }}" - -- name: "6.3.4.10 | PATCH | Ensure audit tools group owner is configured" - when: rhel9cis_rule_6_3_4_10 - tags: - - level2-server - - level2-workstation - - patch - - auditd - - rule_6.3.4.10 - - NIST800-53R5_AU-3 - ansible.builtin.file: - path: "{{ item }}" - group: root - loop: "{{ audit_bins }}" diff --git a/tasks/section_6/main.yml b/tasks/section_6/main.yml index dbff078..35328e5 100644 --- a/tasks/section_6/main.yml +++ b/tasks/section_6/main.yml @@ -1,47 +1,7 @@ --- -- name: "SECTION | 6.1 | Configure Integrity Checking" - ansible.builtin.import_tasks: - file: cis_6.1.x.yml +- name: "SECTION | 6.1 | System File Permissions" + ansible.builtin.import_tasks: cis_6.1.x.yml -- name: "SECTION | 6.2.1 | Configure systemd-journald service" - when: rhel9cis_syslog == 'journald' - ansible.builtin.import_tasks: - file: cis_6.2.1.x.yml - -- name: "SECTION | 6.2.2.1.x | Configure journald-remote" - when: rhel9cis_syslog == 'journald' - ansible.builtin.import_tasks: - file: cis_6.2.2.1.x.yml - -- name: "SECTION | 6.2.2.x | Configure journald" - when: rhel9cis_syslog == 'journald' - ansible.builtin.import_tasks: - file: cis_6.2.2.x.yml - -- name: "SECTION | 6.2.3 | Configure rsyslog" - when: - - rhel9cis_syslog == 'rsyslog' - - rhel9cis_rsyslog_ansiblemanaged - ansible.builtin.import_tasks: - file: cis_6.2.3.x.yml - -- name: "SECTION | 6.2.4.1 | Configure Logfiles" - ansible.builtin.import_tasks: - file: cis_6.2.4.1.yml - -- name: "SECTION | 6.3.1 | Configure auditd Service" - ansible.builtin.import_tasks: - file: cis_6.3.1.x.yml - -- name: "SECTION | 6.3.2 | Configure Data Retention" - ansible.builtin.import_tasks: - file: cis_6.3.2.x.yml - -- name: "SECTION | 6.3.3 | Configure auditd Rules" - ansible.builtin.import_tasks: - file: cis_6.3.3.x.yml - -- name: "SECTION | 6.3.4 | Configure auditd File Access" - ansible.builtin.import_tasks: - file: cis_6.3.4.x.yml +- name: "SECTION | 6.2 | User and Group Settings" + ansible.builtin.import_tasks: cis_6.2.x.yml diff --git a/tasks/section_7/cis_7.1.x.yml b/tasks/section_7/cis_7.1.x.yml deleted file mode 100644 index b23fb89..0000000 --- a/tasks/section_7/cis_7.1.x.yml +++ /dev/null @@ -1,327 +0,0 @@ ---- - -- name: "7.1.1 | PATCH | Ensure permissions on /etc/passwd are configured" - when: - - rhel9cis_rule_7_1_1 - tags: - - level1-server - - level1-workstation - - patch - - permissions - - rule_7.1.1 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/passwd - owner: root - group: root - mode: 'u-x,go-wx' - -- name: "7.1.2 | PATCH | Ensure permissions on /etc/passwd- are configured" - when: - - rhel9cis_rule_7_1_2 - tags: - - level1-server - - level1-workstation - - patch - - permissions - - rule_7.1.2 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/passwd- - owner: root - group: root - mode: 'u-x,go-wx' - -- name: "7.1.3 | PATCH | Ensure permissions on /etc/group are configured" - when: - - rhel9cis_rule_7_1_3 - tags: - - level1-server - - level1-workstation - - patch - - permissions - - rule_7.1.3 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/group - owner: root - group: root - mode: 'u-x,go-wx' - -- name: "7.1.4 | PATCH | Ensure permissions on /etc/group- are configured" - when: - - rhel9cis_rule_7_1_4 - tags: - - level1-server - - level1-workstation - - patch - - permissionss - - rule_7.1.4 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/group- - owner: root - group: root - mode: 'u-x,go-wx' - -- name: "7.1.5 | PATCH | Ensure permissions on /etc/shadow are configured" - when: - - rhel9cis_rule_7_1_5 - tags: - - level1-server - - level1-workstation - - patch - - permissions - - rule_7.1.5 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/shadow - owner: root - group: root - mode: 'ugo-rwx' - -- name: "7.1.6 | PATCH | Ensure permissions on /etc/shadow- are configured" - when: - - rhel9cis_rule_7_1_6 - tags: - - level1-server - - level1-workstation - - patch - - permissions - - rule_7.1.6 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/shadow- - owner: root - group: root - mode: 'ugo-rwx' - -- name: "7.1.7 | PATCH | Ensure permissions on /etc/gshadow are configured" - when: - - rhel9cis_rule_7_1_7 - tags: - - level1-server - - level1-workstation - - patch - - permissions - - rule_7.1.7 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/gshadow - owner: root - group: root - mode: 'ugo-rwx' - -- name: "7.1.8 | PATCH | Ensure permissions on /etc/gshadow- are configured" - when: - - rhel9cis_rule_7_1_8 - tags: - - level1-server - - level1-workstation - - patch - - permissions - - rule_7.1.8 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/gshadow- - owner: root - group: root - mode: 'ugo-rwx' - -- name: "7.1.9 | PATCH | Ensure permissions on /etc/shells are configured" - when: - - rhel9cis_rule_7_1_9 - tags: - - level1-server - - level1-workstation - - patch - - permissions - - rule_7.1.9 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/shells - owner: root - group: root - mode: 'u-x,go-wx' - -- name: "7.1.10 | PATCH | Ensure permissions on /etc/security/opasswd are configured" - when: - - rhel9cis_rule_7_1_10 - tags: - - level1-server - - level1-workstation - - patch - - permissions - - rule_7.1.10 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - ansible.builtin.file: - path: /etc/security/opasswd - owner: root - group: root - mode: 'u-x,go-wx' - failed_when: discovered_file_exists.state not in '[ file, absent ]' - register: discovered_file_exists - -- name: "7.1.11 | PATCH | Ensure world writable files and directories are secured" - when: - - rhel9cis_rule_7_1_11 - tags: - - level1-server - - level1-workstation - - patch - - files - - permissions - - rule_7.1.11 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - block: - - name: "7.1.11 | AUDIT | Ensure world writable files and directories are secured | Get list of world-writable files" - ansible.builtin.shell: df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -0002 - failed_when: false - changed_when: false - register: discovered_world_writable - - - name: "7.1.11 | PATCH | Ensure no world writable files exist | Adjust world-writable files if they exist (Configurable)" - when: - - discovered_world_writable.stdout_lines is defined - - discovered_world_writable.stdout_lines | length > 0 - - rhel9cis_no_world_write_adjust - ansible.builtin.file: - path: '{{ item }}' - mode: 'o-w' - state: touch - loop: "{{ discovered_world_writable.stdout_lines }}" - - - name: "7.1.11 | PATCH | Ensure no world writable files exist | Adjust world-writable directories add sticky bit" - ansible.builtin.shell: df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type d -perm -o+w ! -perm -1002 2>/dev/null | xargs chmod a+t - failed_when: discovered_set_stickybit.rc not in [ 0, 123 ] - changed_when: discovered_set_stickybit.rc == 0 - register: discovered_set_stickybit - -- name: "7.1.12 | PATCH | Ensure no files or directories without an owner and a group exist" - when: - - rhel9cis_rule_7_1_12 - tags: - - level1-server - - level1-workstation - - patch - - rule_7.1.12 - - permissions - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - warn_control_id: '7.1.12' - block: - - name: "7.1.12 | AUDIT | Ensure no files or directories without an owner and a group exist | Get list files or directories" - ansible.builtin.command: find {{ rhel9cis_exclude_unowned_search_path }} {{ item.mount }} -xdev \( -nouser -o -nogroup \) -not -fstype nfs - changed_when: false - failed_when: false - check_mode: false - register: discovered_unowned_files - with_items: - - "{{ ansible_facts.mounts }}" - loop_control: - label: "{{ item.mount }}" - - - name: "7.1.12 | AUDIT | Ensure no files or directories without an owner and a group exist | Flatten no_user_items results for easier use" - ansible.builtin.set_fact: - discovered_unowned_files_flatten: "{{ discovered_unowned_files.results | selectattr('stdout_lines', 'defined') | map(attribute='stdout_lines') | flatten }}" - - - name: "7.1.12 | AUDIT | Ensure no files or directories without an owner and a group exist | Alert on unowned files and directories" - when: - - not rhel9cis_ownership_adjust - - discovered_unowned_files_flatten | length > 0 - ansible.builtin.debug: - msg: - - "Warning!! You have unowned files and are configured to not auto-remediate for this task" - - "Please review the files/directories below and assign an owner" - - "{{ discovered_unowned_files_flatten }}" - - - name: "7.1.12 | PATCH | Ensure no files or directories without an owner and a group exist | Set files/directories to configured owner and group" - when: - - rhel9cis_ownership_adjust - - discovered_unowned_files_flatten | length > 0 - ansible.builtin.file: - path: "{{ item }}" - owner: "{{ rhel9cis_unowned_owner }}" - group: "{{ rhel9cis_unowned_group }}" - with_items: - - "{{ discovered_unowned_files_flatten }}" - - - name: "7.1.12 | AUDIT | Ensure no files or directories without an owner and a group exist | Warn Count" - when: - - not rhel9cis_ownership_adjust - - discovered_unowned_files_flatten | length > 0 - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "7.1.13 | AUDIT | Ensure SUID and SGID files are reviewed" - when: - - rhel9cis_rule_7_1_13 - tags: - - level1-server - - level1-workstation - - audit - - rule_7.1.13 - - permissions - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - - NIST800-53R5_AC-3 - - NIST800-53R5_MP-2 - vars: - warn_control_id: '7.1.13' - block: - - name: "7.1.13 | AUDIT | Ensure SUID and SGID files are reviewed | Find SUID and SGID" - ansible.builtin.command: find {{ item.mount }} -xdev -type f -perm \( -02000 or -04000 \) -not -fstype nfs - changed_when: false - failed_when: false - check_mode: false - register: discovered_suid_sgid_files - with_items: - - "{{ ansible_facts.mounts }}" - loop_control: - label: "{{ item.mount }}" - - - name: "7.1.13 | AUDIT | Audit SUID executables | Flatten suid_executables results for easier use" - ansible.builtin.set_fact: - discovered_suid_sgid_files_flatten: "{{ discovered_suid_sgid_files.results | selectattr('stdout_lines', 'defined') | map(attribute='stdout_lines') | flatten }}" - - - name: "7.1.13 | AUDIT | Audit SUID executables | Alert SUID executables exist" - when: - - discovered_suid_sgid_files_flatten | length > 0 - - not rhel9cis_suid_sgid_adjust - ansible.builtin.debug: - msg: - - "Warning!! You have SUID executables" - - "The files are listed below, please confirm the integrity of these binaries" - - "{{ discovered_suid_sgid_files_flatten }}" - - - name: "7.1.13 | PATCH | Audit SUID executables | Remove SUID bit" - when: - - rhel9cis_suid_sgid_adjust - - discovered_suid_sgid_files_flatten | length > 0 - ansible.builtin.file: - path: "{{ item }}" - mode: 'u-s' - with_items: - - "{{ discovered_suid_sgid_files_flatten }}" - - - name: "7.1.13 | AUDIT | Audit SUID executables | Warn Count" - ansible.builtin.import_tasks: - file: warning_facts.yml - when: - - discovered_suid_sgid_files_flatten | length > 0 - - not rhel9cis_suid_sgid_adjust diff --git a/tasks/section_7/cis_7.2.x.yml b/tasks/section_7/cis_7.2.x.yml deleted file mode 100644 index debc9a6..0000000 --- a/tasks/section_7/cis_7.2.x.yml +++ /dev/null @@ -1,358 +0,0 @@ ---- - -- name: "7.2.1 | AUDIT | Ensure accounts in /etc/passwd use shadowed passwords" - when: - - rhel9cis_rule_7_2_1 - tags: - - level1-server - - level1-workstation - - audit - - rule_7.2.1 - - user_accounts - - NIST800-53R5_IA-5 - vars: - warn_control_id: '7.2.1' - block: - - name: "7.2.1 | AUDIT | Ensure accounts in /etc/passwd use shadowed passwords | Get users not using shadowed passwords" - ansible.builtin.shell: awk -F':' '($2 != "x" ) { print $1}' /etc/passwd - changed_when: false - failed_when: false - register: discovered_nonshadowed_users - - - name: "7.2.1 | AUDIT | Ensure accounts in /etc/passwd use shadowed passwords | Warn on findings" - when: discovered_nonshadowed_users.stdout | length > 0 - ansible.builtin.debug: - msg: - - "Warning!! You have users that are not using a shadowed password. Please convert the below accounts to use a shadowed password" - - "{{ discovered_nonshadowed_users.stdout_lines }}" - - - name: "7.2.1 | WARNING | Ensure accounts in /etc/passwd use shadowed passwords | warn_count" - when: discovered_nonshadowed_users.stdout | length > 0 - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "7.2.2 | PATCH | Ensure /etc/shadow password fields are not empty" - when: - - rhel9cis_rule_7_2_2 - tags: - - level1-server - - level1-workstation - - patch - - rule_7.2.2 - - user - - permissions - - NIST800-53R5_IA-5 - block: - - name: "7.2.2 | AUDIT | Ensure /etc/shadow password fields are not empty | Find users with no password" - ansible.builtin.shell: awk -F":" '($2 == "" ) { print $1 }' /etc/shadow - changed_when: false - check_mode: false - register: discovered_empty_password_acct - - - name: "7.2.2 | PATCH | Ensure /etc/shadow password fields are not empty | Lock users with empty password" - when: discovered_empty_password_acct.stdout | length > 0 - ansible.builtin.user: - name: "{{ item }}" - password_lock: true - loop: - - "{{ discovered_empty_password_acct.stdout_lines }}" - -- name: "7.2.3 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group" - when: - - rhel9cis_rule_7_2_3 - tags: - - level1-server - - level1-workstation - - audit - - rule_7.2.3 - - groups - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - vars: - warn_control_id: '7.2.3' - block: - - name: "7.2.3 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group | Check /etc/passwd entries" - ansible.builtin.shell: pwck -r | grep 'no group' | awk '{ gsub("[:\47]",""); print $2}' - changed_when: false - failed_when: false - check_mode: false - register: discovered_passwd_gid_check - - - name: "7.2.3 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group | Print warning about users with invalid GIDs missing GID entries in /etc/group" - when: discovered_passwd_gid_check.stdout | length > 0 - ansible.builtin.debug: - msg: "Warning!! The following users have non-existent GIDs (Groups): {{ discovered_passwd_gid_check.stdout_lines | join(', ') }}" - - - name: "7.2.3 | WARNING | Ensure all groups in /etc/passwd exist in /etc/group | warn_count" - when: discovered_passwd_gid_check.stdout | length > 0 - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "7.2.4 | AUDIT | Ensure no duplicate UIDs exist" - when: - - rhel9cis_rule_7_2_4 - tags: - - level1-server - - level1-workstation - - audit - - rule_7.2.4 - - user - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - vars: - warn_control_id: '7.2.4' - block: - - name: "7.2.4 | AUDIT | Ensure no duplicate UIDs exist | Check for duplicate UIDs" - ansible.builtin.shell: "pwck -r | awk -F: '{if ($3 in uid) print $1 ; else uid[$3]}' /etc/passwd" - changed_when: false - failed_when: false - check_mode: false - register: discovered_user_uid_check - - - name: "7.2.4 | AUDIT | Ensure no duplicate UIDs exist | Print warning about users with duplicate UIDs" - when: discovered_user_uid_check.stdout | length > 0 - ansible.builtin.debug: - msg: "Warning!! The following users have UIDs that are duplicates: {{ discovered_user_uid_check.stdout_lines }}" - - - name: "7.2.4 | AUDIT | Ensure no duplicate UIDs exist | Set warning count" - when: discovered_user_uid_check.stdout | length > 0 - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "7.2.5 | AUDIT | Ensure no duplicate GIDs exist" - when: - - rhel9cis_rule_7_2_5 - tags: - - level1-server - - level1-workstation - - audit - - rule_7.2.5 - - groups - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - vars: - warn_control_id: '7.2.5' - block: - - name: "7.2.5 | AUDIT | Ensure no duplicate GIDs exist | Check for duplicate GIDs" - ansible.builtin.shell: "pwck -r | awk -F: '{if ($3 in users) print $1 ; else users[$3]}' /etc/group" - changed_when: false - failed_when: false - check_mode: false - register: discovered_user_gid_check - - - name: "7.2.5 | AUDIT | Ensure no duplicate GIDs exist | Print warning about users with duplicate GIDs" - when: discovered_user_gid_check.stdout | length > 0 - ansible.builtin.debug: - msg: "Warning!! The following groups have duplicate GIDs: {{ discovered_user_gid_check.stdout_lines }}" - - - name: "7.2.5 | AUDIT | Ensure no duplicate GIDs exist | Set warning count" - when: discovered_user_gid_check.stdout | length > 0 - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "7.2.6 | AUDIT | Ensure no duplicate user names exist" - vars: - warn_control_id: '7.2.6' - when: - - rhel9cis_rule_7_2_6 - tags: - - level1-server - - level1-workstation - - audit - - rule_7.2.6 - - user - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - block: - - name: "7.2.6 | AUDIT | Ensure no duplicate user names exist | Check for duplicate User Names" - ansible.builtin.shell: "pwck -r | awk -F: '{if ($1 in users) print $1 ; else users[$1]}' /etc/passwd" - changed_when: false - failed_when: false - check_mode: false - register: discovered_username_check - - - name: "7.2.6 | WARNING | Ensure no duplicate user names exist | Print warning about users with duplicate User Names" - when: discovered_username_check.stdout | length > 0 - ansible.builtin.debug: - msg: "Warning!! The following user names are duplicates: {{ discovered_user_username_check.stdout_lines }}" - - - name: "7.2.6 | WARNING | Ensure no duplicate user names exist | Set warning count" - when: discovered_username_check.stdout | length > 0 - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "7.2.7 | AUDIT | Ensure no duplicate group names exist" - when: - - rhel9cis_rule_7_2_7 - tags: - - level1-server - - level1-workstation - - audit - - rule_7.2.7 - - groups - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - vars: - warn_control_id: '7.2.7' - block: - - name: "7.2.7 | AUDIT | Ensure no duplicate group names exist | Check for duplicate group names" - ansible.builtin.shell: 'getent passwd | cut -d: -f1 | sort -n | uniq -d' - changed_when: false - failed_when: false - check_mode: false - register: discovered_group_check - - - name: "7.2.7 | AUDIT | Ensure no duplicate group names exist | Print warning about users with duplicate group names" - when: discovered_group_check.stdout | length > 0 - ansible.builtin.debug: - msg: "Warning!! The following group names are duplicates: {{ discovered_group_check.stdout_lines }}" - - - name: "7.2.7 | AUDIT | Ensure no duplicate group names exist | Set warning count" - when: discovered_group_check.stdout | length > 0 - ansible.builtin.import_tasks: - file: warning_facts.yml - -- name: "7.2.8 | PATCH | Ensure local interactive user home directories are configured" - when: - - rhel9cis_rule_7_2_8 - tags: - - level1-server - - level1-workstation - - patch - - users - - rule_7.2.8 - block: - - name: "7.2.8 | PATCH | Ensure local interactive user home directories are configured | Create dir if absent" # noqa risky-file-permissions - ansible.builtin.file: - path: "{{ item.dir }}" - state: directory - owner: "{{ item.id }}" - group: "{{ item.gid }}" - loop: "{{ prelim_captured_passwd_data | selectattr('uid', '>=', prelim_min_int_uid | int) | selectattr('uid', '<=', prelim_max_int_uid | int) | list }}" - loop_control: - label: "{{ item.id }}" - - # set default ACLs so the homedir has an effective umask of 0027 - - name: "7.2.8 | PATCH | Ensure local interactive user home directories are configured | Set group ACL" - when: not system_is_container - ansible.posix.acl: - path: "{{ item }}" - default: true - etype: group - permissions: rx - state: present - loop: "{{ prelim_interactive_users | map(attribute='home') | list }}" - - - name: "7.2.8 | PATCH | Ensure local interactive user home directories are configured | Set other ACL" - when: not system_is_container - ansible.posix.acl: - path: "{{ item }}" - default: true - etype: other - permissions: 0 - state: present - loop: "{{ prelim_interactive_users | map(attribute='home') | list }}" - -- name: "7.2.9 | PATCH | Ensure local interactive user dot files access is configured" - when: - - rhel9cis_rule_7_2_9 - - rhel9cis_disruption_high - tags: - - level1-server - - level1-workstation - - patch - - rule_7.2.9 - - user - - NIST800-53R5_CM-1 - - NIST800-53R5_CM-2 - - NIST800-53R5_CM-6 - - NIST800-53R5_CM-7 - - NIST800-53R5_IA-5 - vars: - warn_control_id: '7.2.9' - block: - - name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured" - ansible.builtin.shell: find {{ prelim_interactive_users_home.stdout_lines | list | join(' ') }} -name "\.*" -type f - changed_when: false - failed_when: discovered_homedir_hidden_files.rc not in [ 0, 1 ] - check_mode: false - register: discovered_homedir_hidden_files - - - name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Warning on files found" - when: - - discovered_homedir_hidden_files.stdout | length > 0 - - not rhel9cis_dotperm_ansiblemanaged - ansible.builtin.debug: - msg: - - "Warning!! Please investigate that hidden files found in users home directories match control requirements." - - - name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Set warning count" - when: - - discovered_homedir_hidden_files.stdout | length > 0 - - not rhel9cis_dotperm_ansiblemanaged - ansible.builtin.import_tasks: - file: warning_facts.yml - - - name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured" - when: - - discovered_homedir_hidden_files.stdout | length > 0 - - rhel9cis_dotperm_ansiblemanaged - block: - - name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Changes files if configured .bash_history & .netrc" - when: - - discovered_homedir_hidden_files.stdout | length > 0 - - item | basename in ['.bash_history','.netrc'] - ansible.builtin.file: - path: "{{ item }}" - mode: 'u-x,go-rwx' - failed_when: discovered_dot_bash_history_to_change.state not in '[ file, absent ]' - register: discovered_dot_bash_history_to_change - loop: "{{ discovered_homedir_hidden_files.stdout_lines }}" - - - name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Changes files if configured file mode" - ansible.builtin.file: - path: '{{ item }}' - mode: 'u-x,go-wx' - failed_when: discovered_dot_bash_history_to_change.state not in '[ file, absent ]' - register: discovered_dot_bash_history_to_change - loop: "{{ discovered_homedir_hidden_files.stdout_lines }}" - - - name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Changes files ownerships" - ansible.builtin.file: - path: "{{ item }}" - owner: "{{ prelim_captured_passwd_data | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='uid') | last }}" - group: "{{ prelim_captured_passwd_data | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='gid') | last }}" - failed_when: discovered_dot_bash_history_to_change.state not in '[ file, absent ]' - register: discovered_dot_bash_history_to_change - loop: "{{ discovered_homedir_hidden_files.stdout_lines }}" - - - name: "7.2.9 | PATCH | Ensure local interactive user dot files access is configured | Changes files if configured" - ansible.builtin.file: - path: '{{ item }}' - mode: 'go-w' - owner: "{{ prelim_captured_passwd_data | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='uid') | last }}" - group: "{{ prelim_captured_passwd_data | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='gid') | last }}" - with_items: "{{ discovered_homedir_hidden_files.stdout_lines }}" - - - name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | rename .forward or .rhosts files" - when: - - item | basename in ['.forward','.rhosts'] - - item is not search ("CIS") - ansible.builtin.command: "mv {{ item }} {{ item }}_CIS_TOBEREVIEWED" - changed_when: true - loop: "{{ discovered_homedir_hidden_files.stdout_lines }}" diff --git a/tasks/section_7/main.yml b/tasks/section_7/main.yml deleted file mode 100644 index 2d1247a..0000000 --- a/tasks/section_7/main.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- - -- name: "SECTION | 7.1 | System File Permissions" - ansible.builtin.import_tasks: - file: cis_7.1.x.yml - -- name: "SECTION | 7.2 | Local User and Group Settings" - ansible.builtin.import_tasks: - file: cis_7.2.x.yml diff --git a/tasks/warning_facts.yml b/tasks/warning_facts.yml index 108cb89..6e80487 100644 --- a/tasks/warning_facts.yml +++ b/tasks/warning_facts.yml @@ -1,4 +1,5 @@ --- + # This task is used to create variables used in giving a warning summary for manual tasks # that need attention # @@ -13,7 +14,7 @@ # # warn_count the main variable for the number of warnings and each time a warn_control_id is added # the count increases by a value of 1 -- name: "{{ warn_control_id }} | AUDIT | Set fact for manual task warning." # noqa name[template] +- name: "{{ warn_control_id }} | AUDIT | Set fact for manual task warning." ansible.builtin.set_fact: - warn_control_list: "{{ warn_control_list }} [{{ warn_control_id }}]" - warn_count: "{{ warn_count | int + 1 }}" + warn_control_list: "{{ warn_control_list }} [{{ warn_control_id }}]" + warn_count: "{{ warn_count | int + 1 }}" diff --git a/templates/ansible_vars_goss.yml.j2 b/templates/ansible_vars_goss.yml.j2 index cbaa125..8749fc1 100644 --- a/templates/ansible_vars_goss.yml.j2 +++ b/templates/ansible_vars_goss.yml.j2 @@ -1,145 +1,117 @@ ---- + +## This file is managed by Ansible, YOUR CHANGED WILL BE LOST! +## metadata for benchmark + +## metadata for Audit benchmark +benchmark_version: '1.0.0' + +# Set if genuine RHEL (subscription manager check) not for derivatives e.g. CentOS +# If run via script this is discovered and set +host_os_distribution: {{ ansible_distribution | lower }} -# Enable logrunning potential resource intensive tests -run_heavy_tests: {{ audit_run_heavy_tests }} +# timeout for each command to run where set - default = 10seconds/10000ms +timeout_ms: 60000 -# Extend default command timeout for longer running tests -timeout_ms: {{ audit_cmd_timeout }} - -## Switching on/off specific baseline sections -# These variables govern whether the tasks of a particular section are to be executed when running the role. -# E.g: If you want to execute the tasks of Section 1 you should set the "_section1" variable to true. -# If you do not want the tasks from that section to get executed you simply set the variable to "false". +# Taken from LE rhel9-cis rhel9cis_section1: {{ rhel9cis_section1 }} rhel9cis_section2: {{ rhel9cis_section2 }} rhel9cis_section3: {{ rhel9cis_section3 }} rhel9cis_section4: {{ rhel9cis_section4 }} rhel9cis_section5: {{ rhel9cis_section5 }} rhel9cis_section6: {{ rhel9cis_section6 }} -rhel9cis_section7: {{ rhel9cis_section7 }} -# This is used for audit purposes to run only specific level use the tags -# e.g. -# - level1-server -# - level2-workstation rhel9cis_level_1: {{ rhel9cis_level_1 }} rhel9cis_level_2: {{ rhel9cis_level_2 }} -## Section 1.6 - Mandatory Access Control -# This variable governs whether SELinux is disabled or not. If SELinux is NOT DISABLED by setting -# 'rhel9cis_selinux_disable' to 'true', the 1.6 subsection will be executed. rhel9cis_selinux_disable: {{ rhel9cis_selinux_disable }} -# This variable is used in a preliminary task, handling grub2 paths either in case of -# UEFI boot('/etc/grub2-efi.cfg') or in case of BIOS legacy-boot('/etc/grub2.cfg'). + +# to enable rules that may have IO impact on a system e.g. full filesystem scans or CPU heavy +run_heavy_tests: true + +# True is BIOS based system else set to false +{% if rhel9cis_legacy_boot is defined %} rhel9cis_legacy_boot: {{ rhel9cis_legacy_boot }} +{% endif %} -## Benchmark name used by auditing control role -# The audit variable found at the base -## metadata for Audit benchmark -benchmark_version: {{ benchmark_version }} - -benchmark: RHEL9-CIS +rhel9cis_set_boot_pass: {{ rhel9cis_set_boot_pass }} # These variables correspond with the CIS rule IDs or paragraph numbers defined in # the CIS benchmark documents. # PLEASE NOTE: These work in coordination with the section # group variables and tags. # You must enable an entire section in order for the variables below to take effect. - -# Section 1 is Initial setup (FileSystem Configuration, Configure Software Updates, Filesystem Integrity Checking, Secure Boot Settings, -# Additional Process Hardening, Mandatory Access Control, Command Line Warning Banners, and GNOME Display Manager) -# Filesystem kernel modules +# Section 1 rules +# 1.1.1 Disable unused filesystems rhel9cis_rule_1_1_1_1: {{ rhel9cis_rule_1_1_1_1 }} rhel9cis_rule_1_1_1_2: {{ rhel9cis_rule_1_1_1_2 }} -rhel9cis_rule_1_1_1_3: {{ rhel9cis_rule_1_1_1_3 }} -rhel9cis_rule_1_1_1_4: {{ rhel9cis_rule_1_1_1_4 }} -rhel9cis_rule_1_1_1_5: {{ rhel9cis_rule_1_1_1_5 }} -rhel9cis_rule_1_1_1_6: {{ rhel9cis_rule_1_1_1_6 }} -rhel9cis_rule_1_1_1_7: {{ rhel9cis_rule_1_1_1_7 }} -rhel9cis_rule_1_1_1_8: {{ rhel9cis_rule_1_1_1_8 }} -rhel9cis_rule_1_1_1_9: {{ rhel9cis_rule_1_1_1_9 }} -# Filesystems -# /tmp -rhel9cis_rule_1_1_2_1_1: {{ rhel9cis_rule_1_1_2_1_1 }} -rhel9cis_rule_1_1_2_1_2: {{ rhel9cis_rule_1_1_2_1_2 }} -rhel9cis_rule_1_1_2_1_3: {{ rhel9cis_rule_1_1_2_1_3 }} -rhel9cis_rule_1_1_2_1_4: {{ rhel9cis_rule_1_1_2_1_4 }} -# /dev/shm -rhel9cis_rule_1_1_2_2_1: {{ rhel9cis_rule_1_1_2_2_1 }} -rhel9cis_rule_1_1_2_2_2: {{ rhel9cis_rule_1_1_2_2_2 }} -rhel9cis_rule_1_1_2_2_3: {{ rhel9cis_rule_1_1_2_2_3 }} -rhel9cis_rule_1_1_2_2_4: {{ rhel9cis_rule_1_1_2_2_4 }} -# /home -rhel9cis_rule_1_1_2_3_1: {{ rhel9cis_rule_1_1_2_3_1 }} -rhel9cis_rule_1_1_2_3_2: {{ rhel9cis_rule_1_1_2_3_2 }} -rhel9cis_rule_1_1_2_3_3: {{ rhel9cis_rule_1_1_2_3_3 }} -# /var -rhel9cis_rule_1_1_2_4_1: {{ rhel9cis_rule_1_1_2_4_1 }} -rhel9cis_rule_1_1_2_4_2: {{ rhel9cis_rule_1_1_2_4_2 }} -rhel9cis_rule_1_1_2_4_3: {{ rhel9cis_rule_1_1_2_4_3 }} -# /var/tmp -rhel9cis_rule_1_1_2_5_1: {{ rhel9cis_rule_1_1_2_5_1 }} -rhel9cis_rule_1_1_2_5_2: {{ rhel9cis_rule_1_1_2_5_2 }} -rhel9cis_rule_1_1_2_5_3: {{ rhel9cis_rule_1_1_2_5_3 }} -rhel9cis_rule_1_1_2_5_4: {{ rhel9cis_rule_1_1_2_5_4 }} -# /var/log -rhel9cis_rule_1_1_2_6_1: {{ rhel9cis_rule_1_1_2_6_1 }} -rhel9cis_rule_1_1_2_6_2: {{ rhel9cis_rule_1_1_2_6_2 }} -rhel9cis_rule_1_1_2_6_3: {{ rhel9cis_rule_1_1_2_6_3 }} -rhel9cis_rule_1_1_2_6_4: {{ rhel9cis_rule_1_1_2_6_4 }} -# /var/log/audit -rhel9cis_rule_1_1_2_7_1: {{ rhel9cis_rule_1_1_2_7_1 }} -rhel9cis_rule_1_1_2_7_2: {{ rhel9cis_rule_1_1_2_7_2 }} -rhel9cis_rule_1_1_2_7_3: {{ rhel9cis_rule_1_1_2_7_3 }} -rhel9cis_rule_1_1_2_7_4: {{ rhel9cis_rule_1_1_2_7_4 }} - -# Package Mgmt -# Config Pkg Repos -rhel9cis_rule_1_2_1_1: {{ rhel9cis_rule_1_2_1_1 }} -rhel9cis_rule_1_2_1_2: {{ rhel9cis_rule_1_2_1_2 }} -rhel9cis_rule_1_2_1_3: {{ rhel9cis_rule_1_2_1_3 }} -rhel9cis_rule_1_2_1_4: {{ rhel9cis_rule_1_2_1_4 }} -# Package updates -rhel9cis_rule_1_2_2_1: {{ rhel9cis_rule_1_2_2_1 }} - -# Selinux -rhel9cis_rule_1_3_1_1: {{ rhel9cis_rule_1_3_1_1 }} -rhel9cis_rule_1_3_1_2: {{ rhel9cis_rule_1_3_1_2 }} -rhel9cis_rule_1_3_1_3: {{ rhel9cis_rule_1_3_1_3 }} -rhel9cis_rule_1_3_1_4: {{ rhel9cis_rule_1_3_1_4 }} -rhel9cis_rule_1_3_1_5: {{ rhel9cis_rule_1_3_1_5 }} -rhel9cis_rule_1_3_1_6: {{ rhel9cis_rule_1_3_1_6 }} -rhel9cis_rule_1_3_1_7: {{ rhel9cis_rule_1_3_1_7 }} -rhel9cis_rule_1_3_1_8: {{ rhel9cis_rule_1_3_1_8 }} - -# Bootloader +# 1.1.2 Configure /tmp +rhel9cis_rule_1_1_2_1: {{ rhel9cis_rule_1_1_2_1 }} +rhel9cis_rule_1_1_2_2: {{ rhel9cis_rule_1_1_2_2 }} +rhel9cis_rule_1_1_2_3: {{ rhel9cis_rule_1_1_2_3 }} +rhel9cis_rule_1_1_2_4: {{ rhel9cis_rule_1_1_2_4 }} +# 1.1.3 Configure /var +rhel9cis_rule_1_1_3_1: {{ rhel9cis_rule_1_1_3_1 }} +rhel9cis_rule_1_1_3_2: {{ rhel9cis_rule_1_1_3_2 }} +rhel9cis_rule_1_1_3_3: {{ rhel9cis_rule_1_1_3_3 }} +# 1.1.4 Configure /var/tmp +rhel9cis_rule_1_1_4_1: {{ rhel9cis_rule_1_1_4_1 }} +rhel9cis_rule_1_1_4_2: {{ rhel9cis_rule_1_1_4_2 }} +rhel9cis_rule_1_1_4_3: {{ rhel9cis_rule_1_1_4_3 }} +rhel9cis_rule_1_1_4_4: {{ rhel9cis_rule_1_1_4_4 }} +# 1.1.5 Configure /var/log +rhel9cis_rule_1_1_5_1: {{ rhel9cis_rule_1_1_5_1 }} +rhel9cis_rule_1_1_5_2: {{ rhel9cis_rule_1_1_5_2 }} +rhel9cis_rule_1_1_5_3: {{ rhel9cis_rule_1_1_5_3 }} +rhel9cis_rule_1_1_5_4: {{ rhel9cis_rule_1_1_5_4 }} +# 1.1.6 Configure /var/log/audit +rhel9cis_rule_1_1_6_1: {{ rhel9cis_rule_1_1_6_1 }} +rhel9cis_rule_1_1_6_2: {{ rhel9cis_rule_1_1_6_2 }} +rhel9cis_rule_1_1_6_3: {{ rhel9cis_rule_1_1_6_3 }} +rhel9cis_rule_1_1_6_4: {{ rhel9cis_rule_1_1_6_4 }} +# 1.1.7 Configure /home +rhel9cis_rule_1_1_7_1: {{ rhel9cis_rule_1_1_7_1 }} +rhel9cis_rule_1_1_7_2: {{ rhel9cis_rule_1_1_7_2 }} +rhel9cis_rule_1_1_7_3: {{ rhel9cis_rule_1_1_7_3 }} +# 1.1.8 Configure /dev/shm +rhel9cis_rule_1_1_8_1: {{ rhel9cis_rule_1_1_8_1 }} +rhel9cis_rule_1_1_8_2: {{ rhel9cis_rule_1_1_8_2 }} +rhel9cis_rule_1_1_8_3: {{ rhel9cis_rule_1_1_8_3 }} +rhel9cis_rule_1_1_8_4: {{ rhel9cis_rule_1_1_8_4 }} +# 1.9 usb-storage +rhel9cis_rule_1_1_9: {{ rhel9cis_rule_1_1_9 }} +# 1.2 Configure Software Updates +rhel9cis_rule_1_2_1: {{ rhel9cis_rule_1_2_1 }} +rhel9cis_rule_1_2_2: {{ rhel9cis_rule_1_2_2 }} +rhel9cis_rule_1_2_3: {{ rhel9cis_rule_1_2_3 }} +rhel9cis_rule_1_2_4: {{ rhel9cis_rule_1_2_4 }} +# 1.3 Filesystem Integrity Checking +rhel9cis_rule_1_3_1: {{ rhel9cis_rule_1_3_1 }} +rhel9cis_rule_1_3_2: {{ rhel9cis_rule_1_3_2 }} +rhel9cis_rule_1_3_3: {{ rhel9cis_rule_1_3_3 }} +# 1.4 Secure Boot Settings rhel9cis_rule_1_4_1: {{ rhel9cis_rule_1_4_1 }} rhel9cis_rule_1_4_2: {{ rhel9cis_rule_1_4_2 }} - -# Additional Process Hardening +# 1.5 Additional Process Hardening rhel9cis_rule_1_5_1: {{ rhel9cis_rule_1_5_1 }} rhel9cis_rule_1_5_2: {{ rhel9cis_rule_1_5_2 }} rhel9cis_rule_1_5_3: {{ rhel9cis_rule_1_5_3 }} -rhel9cis_rule_1_5_4: {{ rhel9cis_rule_1_5_4 }} - -# Config system wide Crypto -rhel9cis_rule_1_6_1: {{ rhel9cis_rule_1_6_1 }} -rhel9cis_rule_1_6_2: {{ rhel9cis_rule_1_6_2 }} -rhel9cis_rule_1_6_3: {{ rhel9cis_rule_1_6_3 }} -rhel9cis_rule_1_6_4: {{ rhel9cis_rule_1_6_4 }} -rhel9cis_rule_1_6_5: {{ rhel9cis_rule_1_6_5 }} -rhel9cis_rule_1_6_6: {{ rhel9cis_rule_1_6_6 }} -rhel9cis_rule_1_6_7: {{ rhel9cis_rule_1_6_7 }} - -# Command line warning banners +# 1.6 Mandatory Access Control +rhel9cis_rule_1_6_1_1: {{ rhel9cis_rule_1_6_1_1 }} +rhel9cis_rule_1_6_1_2: {{ rhel9cis_rule_1_6_1_2 }} +rhel9cis_rule_1_6_1_3: {{ rhel9cis_rule_1_6_1_3 }} +rhel9cis_rule_1_6_1_4: {{ rhel9cis_rule_1_6_1_4 }} +rhel9cis_rule_1_6_1_5: {{ rhel9cis_rule_1_6_1_5 }} +rhel9cis_rule_1_6_1_6: {{ rhel9cis_rule_1_6_1_6 }} +rhel9cis_rule_1_6_1_7: {{ rhel9cis_rule_1_6_1_7 }} +rhel9cis_rule_1_6_1_8: {{ rhel9cis_rule_1_6_1_8 }} +# 1.7 Command Line Warning Banners rhel9cis_rule_1_7_1: {{ rhel9cis_rule_1_7_1 }} rhel9cis_rule_1_7_2: {{ rhel9cis_rule_1_7_2 }} rhel9cis_rule_1_7_3: {{ rhel9cis_rule_1_7_3 }} rhel9cis_rule_1_7_4: {{ rhel9cis_rule_1_7_4 }} rhel9cis_rule_1_7_5: {{ rhel9cis_rule_1_7_5 }} rhel9cis_rule_1_7_6: {{ rhel9cis_rule_1_7_6 }} - -# Gnome Display Manager +# 1.8 Gnome Display Manager rhel9cis_rule_1_8_1: {{ rhel9cis_rule_1_8_1 }} rhel9cis_rule_1_8_2: {{ rhel9cis_rule_1_8_2 }} rhel9cis_rule_1_8_3: {{ rhel9cis_rule_1_8_3 }} @@ -150,68 +122,53 @@ rhel9cis_rule_1_8_7: {{ rhel9cis_rule_1_8_7 }} rhel9cis_rule_1_8_8: {{ rhel9cis_rule_1_8_8 }} rhel9cis_rule_1_8_9: {{ rhel9cis_rule_1_8_9 }} rhel9cis_rule_1_8_10: {{ rhel9cis_rule_1_8_10 }} +# 1.9 Ensure updates, patches, and additional security software are installed +rhel9cis_rule_1_9: {{ rhel9cis_rule_1_9 }} +# Ensure system-wide crypto policy is not legacy +rhel9cis_rule_1_10: {{ rhel9cis_rule_1_10 }} -# Section 2 rules are controlling Services (Special Purpose Services, and service clients) -## Configure Server Services + +# section 2 +# Services +# 2.1 Time Synchronization rhel9cis_rule_2_1_1: {{ rhel9cis_rule_2_1_1 }} rhel9cis_rule_2_1_2: {{ rhel9cis_rule_2_1_2 }} -rhel9cis_rule_2_1_3: {{ rhel9cis_rule_2_1_3 }} -rhel9cis_rule_2_1_4: {{ rhel9cis_rule_2_1_4 }} -rhel9cis_rule_2_1_5: {{ rhel9cis_rule_2_1_5 }} -rhel9cis_rule_2_1_6: {{ rhel9cis_rule_2_1_6 }} -rhel9cis_rule_2_1_7: {{ rhel9cis_rule_2_1_7 }} -rhel9cis_rule_2_1_8: {{ rhel9cis_rule_2_1_8 }} -rhel9cis_rule_2_1_9: {{ rhel9cis_rule_2_1_9 }} -rhel9cis_rule_2_1_10: {{ rhel9cis_rule_2_1_10 }} -rhel9cis_rule_2_1_11: {{ rhel9cis_rule_2_1_11 }} -rhel9cis_rule_2_1_12: {{ rhel9cis_rule_2_1_12 }} -rhel9cis_rule_2_1_13: {{ rhel9cis_rule_2_1_13 }} -rhel9cis_rule_2_1_14: {{ rhel9cis_rule_2_1_14 }} -rhel9cis_rule_2_1_15: {{ rhel9cis_rule_2_1_15 }} -rhel9cis_rule_2_1_16: {{ rhel9cis_rule_2_1_16 }} -rhel9cis_rule_2_1_17: {{ rhel9cis_rule_2_1_17 }} -rhel9cis_rule_2_1_18: {{ rhel9cis_rule_2_1_18 }} -rhel9cis_rule_2_1_19: {{ rhel9cis_rule_2_1_19 }} -rhel9cis_rule_2_1_20: {{ rhel9cis_rule_2_1_20 }} -rhel9cis_rule_2_1_21: {{ rhel9cis_rule_2_1_21 }} -rhel9cis_rule_2_1_22: {{ rhel9cis_rule_2_1_22 }} - -## Configure Client Services +# 2.2 Special Purpose Services rhel9cis_rule_2_2_1: {{ rhel9cis_rule_2_2_1 }} rhel9cis_rule_2_2_2: {{ rhel9cis_rule_2_2_2 }} rhel9cis_rule_2_2_3: {{ rhel9cis_rule_2_2_3 }} rhel9cis_rule_2_2_4: {{ rhel9cis_rule_2_2_4 }} rhel9cis_rule_2_2_5: {{ rhel9cis_rule_2_2_5 }} - -## Configure Time Synchronization +rhel9cis_rule_2_2_6: {{ rhel9cis_rule_2_2_6 }} +rhel9cis_rule_2_2_7: {{ rhel9cis_rule_2_2_7 }} +rhel9cis_rule_2_2_8: {{ rhel9cis_rule_2_2_8 }} +rhel9cis_rule_2_2_9: {{ rhel9cis_rule_2_2_9 }} +rhel9cis_rule_2_2_10: {{ rhel9cis_rule_2_2_10 }} +rhel9cis_rule_2_2_11: {{ rhel9cis_rule_2_2_11 }} +rhel9cis_rule_2_2_12: {{ rhel9cis_rule_2_2_12 }} +rhel9cis_rule_2_2_13: {{ rhel9cis_rule_2_2_13 }} +rhel9cis_rule_2_2_14: {{ rhel9cis_rule_2_2_14 }} +rhel9cis_rule_2_2_15: {{ rhel9cis_rule_2_2_15 }} +rhel9cis_rule_2_2_16: {{ rhel9cis_rule_2_2_16 }} +rhel9cis_rule_2_2_17: {{ rhel9cis_rule_2_2_17 }} +rhel9cis_rule_2_2_18: {{ rhel9cis_rule_2_2_18 }} +# 2.3 service clients rhel9cis_rule_2_3_1: {{ rhel9cis_rule_2_3_1 }} rhel9cis_rule_2_3_2: {{ rhel9cis_rule_2_3_2 }} rhel9cis_rule_2_3_3: {{ rhel9cis_rule_2_3_3 }} +rhel9cis_rule_2_3_4: {{ rhel9cis_rule_2_3_4 }} -## Job Schedulers -### cron -rhel9cis_rule_2_4_1_1: {{ rhel9cis_rule_2_4_1_1 }} -rhel9cis_rule_2_4_1_2: {{ rhel9cis_rule_2_4_1_2 }} -rhel9cis_rule_2_4_1_3: {{ rhel9cis_rule_2_4_1_3 }} -rhel9cis_rule_2_4_1_4: {{ rhel9cis_rule_2_4_1_4 }} -rhel9cis_rule_2_4_1_5: {{ rhel9cis_rule_2_4_1_5 }} -rhel9cis_rule_2_4_1_6: {{ rhel9cis_rule_2_4_1_6 }} -rhel9cis_rule_2_4_1_7: {{ rhel9cis_rule_2_4_1_7 }} -rhel9cis_rule_2_4_1_8: {{ rhel9cis_rule_2_4_1_8 }} -### at -rhel9cis_rule_2_4_2_1: {{ rhel9cis_rule_2_4_2_1 }} +rhel9cis_rule_2_4: true -# Section 3 Network -## Network Devices +# Section 3 rules +# 3.1 Disable unused network protocols and devices rhel9cis_rule_3_1_1: {{ rhel9cis_rule_3_1_1 }} rhel9cis_rule_3_1_2: {{ rhel9cis_rule_3_1_2 }} rhel9cis_rule_3_1_3: {{ rhel9cis_rule_3_1_3 }} -## Network Kernel Modules +# 3.2 Network Parameters (Host Only) rhel9cis_rule_3_2_1: {{ rhel9cis_rule_3_2_1 }} rhel9cis_rule_3_2_2: {{ rhel9cis_rule_3_2_2 }} -rhel9cis_rule_3_2_3: {{ rhel9cis_rule_3_2_3 }} -rhel9cis_rule_3_2_4: {{ rhel9cis_rule_3_2_4 }} -# Network Kernel Parameters +# 3.3 Network Parameters (Host and Router) rhel9cis_rule_3_3_1: {{ rhel9cis_rule_3_3_1 }} rhel9cis_rule_3_3_2: {{ rhel9cis_rule_3_3_2 }} rhel9cis_rule_3_3_3: {{ rhel9cis_rule_3_3_3 }} @@ -221,24 +178,97 @@ rhel9cis_rule_3_3_6: {{ rhel9cis_rule_3_3_6 }} rhel9cis_rule_3_3_7: {{ rhel9cis_rule_3_3_7 }} rhel9cis_rule_3_3_8: {{ rhel9cis_rule_3_3_8 }} rhel9cis_rule_3_3_9: {{ rhel9cis_rule_3_3_9 }} -rhel9cis_rule_3_3_10: {{ rhel9cis_rule_3_3_10 }} -rhel9cis_rule_3_3_11: {{ rhel9cis_rule_3_3_11 }} +# 3.4.1 Configure firewalld +rhel9cis_rule_3_4_1_1: {{ rhel9cis_rule_3_4_1_1 }} +rhel9cis_rule_3_4_1_2: {{ rhel9cis_rule_3_4_1_2 }} -# Section 4 Firewalls -## Firewall utility -rhel9cis_rule_4_1_1: {{ rhel9cis_rule_4_1_1 }} -rhel9cis_rule_4_1_2: {{ rhel9cis_rule_4_1_2 }} -## Configure firewalld -rhel9cis_rule_4_2_1: {{ rhel9cis_rule_4_2_1 }} -rhel9cis_rule_4_2_2: {{ rhel9cis_rule_4_2_2 }} -# Configure nftables -rhel9cis_rule_4_3_1: {{ rhel9cis_rule_4_3_1 }} -rhel9cis_rule_4_3_2: {{ rhel9cis_rule_4_3_2 }} -rhel9cis_rule_4_3_3: {{ rhel9cis_rule_4_3_3 }} -rhel9cis_rule_4_3_4: {{ rhel9cis_rule_4_3_4 }} +# 3.4.1 Configure nftables +rhel9cis_rule_3_4_2_1: {{ rhel9cis_rule_3_4_2_1 }} +rhel9cis_rule_3_4_2_2: {{ rhel9cis_rule_3_4_2_2 }} +rhel9cis_rule_3_4_2_3: {{ rhel9cis_rule_3_4_2_3 }} +rhel9cis_rule_3_4_2_4: {{ rhel9cis_rule_3_4_2_4 }} +rhel9cis_rule_3_4_2_5: {{ rhel9cis_rule_3_4_2_5 }} +rhel9cis_rule_3_4_2_6: {{ rhel9cis_rule_3_4_2_6 }} +rhel9cis_rule_3_4_2_7: {{ rhel9cis_rule_3_4_2_7 }} -## Section 5 -## 5.1. Configure SSH Server + +# Section 4 rules +# 4.1 Configure System Accounting +rhel9cis_rule_4_1_1_1: {{ rhel9cis_rule_4_1_1_1 }} +rhel9cis_rule_4_1_1_2: {{ rhel9cis_rule_4_1_1_2 }} +rhel9cis_rule_4_1_1_3: {{ rhel9cis_rule_4_1_1_3 }} +rhel9cis_rule_4_1_1_4: {{ rhel9cis_rule_4_1_1_4 }} + +# 4.1.2 Configure Data retention +rhel9cis_rule_4_1_2_1: {{ rhel9cis_rule_4_1_2_1 }} +rhel9cis_rule_4_1_2_2: {{ rhel9cis_rule_4_1_2_2 }} +rhel9cis_rule_4_1_2_3: {{ rhel9cis_rule_4_1_2_3 }} + +# 4.1.3 Configure auditd rules +rhel9cis_rule_4_1_3_1: {{ rhel9cis_rule_4_1_3_1 }} +rhel9cis_rule_4_1_3_2: {{ rhel9cis_rule_4_1_3_2 }} +rhel9cis_rule_4_1_3_3: {{ rhel9cis_rule_4_1_3_3 }} +rhel9cis_rule_4_1_3_4: {{ rhel9cis_rule_4_1_3_4 }} +rhel9cis_rule_4_1_3_5: {{ rhel9cis_rule_4_1_3_5 }} +rhel9cis_rule_4_1_3_6: {{ rhel9cis_rule_4_1_3_6 }} +rhel9cis_rule_4_1_3_7: {{ rhel9cis_rule_4_1_3_7 }} +rhel9cis_rule_4_1_3_8: {{ rhel9cis_rule_4_1_3_8 }} +rhel9cis_rule_4_1_3_9: {{ rhel9cis_rule_4_1_3_9 }} +rhel9cis_rule_4_1_3_10: {{ rhel9cis_rule_4_1_3_10 }} +rhel9cis_rule_4_1_3_11: {{ rhel9cis_rule_4_1_3_11 }} +rhel9cis_rule_4_1_3_12: {{ rhel9cis_rule_4_1_3_12 }} +rhel9cis_rule_4_1_3_13: {{ rhel9cis_rule_4_1_3_13 }} +rhel9cis_rule_4_1_3_14: {{ rhel9cis_rule_4_1_3_14 }} +rhel9cis_rule_4_1_3_15: {{ rhel9cis_rule_4_1_3_15 }} +rhel9cis_rule_4_1_3_16: {{ rhel9cis_rule_4_1_3_16 }} +rhel9cis_rule_4_1_3_17: {{ rhel9cis_rule_4_1_3_17 }} +rhel9cis_rule_4_1_3_18: {{ rhel9cis_rule_4_1_3_18 }} +rhel9cis_rule_4_1_3_19: {{ rhel9cis_rule_4_1_3_19 }} +rhel9cis_rule_4_1_3_20: {{ rhel9cis_rule_4_1_3_20 }} +rhel9cis_rule_4_1_3_21: {{ rhel9cis_rule_4_1_3_21 }} + +# 4.1.4 Configure auditd file Access +rhel9cis_rule_4_1_4_1: {{ rhel9cis_rule_4_1_4_1 }} +rhel9cis_rule_4_1_4_2: {{ rhel9cis_rule_4_1_4_2 }} +rhel9cis_rule_4_1_4_3: {{ rhel9cis_rule_4_1_4_3 }} +rhel9cis_rule_4_1_4_4: {{ rhel9cis_rule_4_1_4_4 }} +rhel9cis_rule_4_1_4_5: {{ rhel9cis_rule_4_1_4_5 }} +rhel9cis_rule_4_1_4_6: {{ rhel9cis_rule_4_1_4_6 }} +rhel9cis_rule_4_1_4_7: {{ rhel9cis_rule_4_1_4_7 }} +rhel9cis_rule_4_1_4_8: {{ rhel9cis_rule_4_1_4_8 }} +rhel9cis_rule_4_1_4_9: {{ rhel9cis_rule_4_1_4_9 }} +rhel9cis_rule_4_1_4_10: {{ rhel9cis_rule_4_1_4_10 }} + +# 4.2.1 Configure rsyslog +rhel9cis_rule_4_2_1_1: {{ rhel9cis_rule_4_2_1_1 }} +rhel9cis_rule_4_2_1_2: {{ rhel9cis_rule_4_2_1_2 }} +rhel9cis_rule_4_2_1_2: {{ rhel9cis_rule_4_2_1_3 }} +rhel9cis_rule_4_2_1_3: {{ rhel9cis_rule_4_2_1_3 }} +rhel9cis_rule_4_2_1_4: {{ rhel9cis_rule_4_2_1_4 }} +rhel9cis_rule_4_2_1_5: {{ rhel9cis_rule_4_2_1_5 }} +rhel9cis_rule_4_2_1_6: {{ rhel9cis_rule_4_2_1_6 }} +rhel9cis_rule_4_2_1_7: {{ rhel9cis_rule_4_2_1_7 }} + +# 4.2.2 Configure journald +rhel9cis_rule_4_2_2_1_1: {{ rhel9cis_rule_4_2_2_1_1 }} +rhel9cis_rule_4_2_2_1_2: {{ rhel9cis_rule_4_2_2_1_2 }} +rhel9cis_rule_4_2_2_1_3: {{ rhel9cis_rule_4_2_2_1_3 }} +rhel9cis_rule_4_2_2_1_4: {{ rhel9cis_rule_4_2_2_1_4 }} +rhel9cis_rule_4_2_2_2: {{ rhel9cis_rule_4_2_2_2 }} +rhel9cis_rule_4_2_2_3: {{ rhel9cis_rule_4_2_2_3 }} +rhel9cis_rule_4_2_2_4: {{ rhel9cis_rule_4_2_2_4 }} +rhel9cis_rule_4_2_2_5: {{ rhel9cis_rule_4_2_2_5 }} +rhel9cis_rule_4_2_2_6: {{ rhel9cis_rule_4_2_2_6 }} +rhel9cis_rule_4_2_2_7: {{ rhel9cis_rule_4_2_2_7 }} +rhel9cis_rule_4_2_3: {{ rhel9cis_rule_4_2_3 }} + +# 4.3 Logrotate +rhel9cis_rule_4_3: {{ rhel9cis_rule_4_3 }} + + +# Section 5 +# Authentication and Authorization +# 5.1 Configure time-based job schedulers rhel9cis_rule_5_1_1: {{ rhel9cis_rule_5_1_1 }} rhel9cis_rule_5_1_2: {{ rhel9cis_rule_5_1_2 }} rhel9cis_rule_5_1_3: {{ rhel9cis_rule_5_1_3 }} @@ -248,20 +278,8 @@ rhel9cis_rule_5_1_6: {{ rhel9cis_rule_5_1_6 }} rhel9cis_rule_5_1_7: {{ rhel9cis_rule_5_1_7 }} rhel9cis_rule_5_1_8: {{ rhel9cis_rule_5_1_8 }} rhel9cis_rule_5_1_9: {{ rhel9cis_rule_5_1_9 }} -rhel9cis_rule_5_1_10: {{ rhel9cis_rule_5_1_10 }} -rhel9cis_rule_5_1_11: {{ rhel9cis_rule_5_1_11 }} -rhel9cis_rule_5_1_12: {{ rhel9cis_rule_5_1_12 }} -rhel9cis_rule_5_1_13: {{ rhel9cis_rule_5_1_13 }} -rhel9cis_rule_5_1_14: {{ rhel9cis_rule_5_1_14 }} -rhel9cis_rule_5_1_15: {{ rhel9cis_rule_5_1_15 }} -rhel9cis_rule_5_1_16: {{ rhel9cis_rule_5_1_16 }} -rhel9cis_rule_5_1_17: {{ rhel9cis_rule_5_1_17 }} -rhel9cis_rule_5_1_18: {{ rhel9cis_rule_5_1_18 }} -rhel9cis_rule_5_1_19: {{ rhel9cis_rule_5_1_19 }} -rhel9cis_rule_5_1_20: {{ rhel9cis_rule_5_1_20 }} -rhel9cis_rule_5_1_21: {{ rhel9cis_rule_5_1_21 }} -rhel9cis_rule_5_1_22: {{ rhel9cis_rule_5_1_22 }} -## 5.2 Configure Privilege Escalation + +# 5.2 Configure SSH Server rhel9cis_rule_5_2_1: {{ rhel9cis_rule_5_2_1 }} rhel9cis_rule_5_2_2: {{ rhel9cis_rule_5_2_2 }} rhel9cis_rule_5_2_3: {{ rhel9cis_rule_5_2_3 }} @@ -269,496 +287,225 @@ rhel9cis_rule_5_2_4: {{ rhel9cis_rule_5_2_4 }} rhel9cis_rule_5_2_5: {{ rhel9cis_rule_5_2_5 }} rhel9cis_rule_5_2_6: {{ rhel9cis_rule_5_2_6 }} rhel9cis_rule_5_2_7: {{ rhel9cis_rule_5_2_7 }} -# 5.3.1.x Configure PAM software packages -rhel9cis_rule_5_3_1_1: {{ rhel9cis_rule_5_3_1_1 }} -rhel9cis_rule_5_3_1_2: {{ rhel9cis_rule_5_3_1_2 }} -rhel9cis_rule_5_3_1_3: {{ rhel9cis_rule_5_3_1_3 }} -# 5.3.2 Configure authselect -rhel9cis_rule_5_3_2_1: {{ rhel9cis_rule_5_3_2_1 }} -rhel9cis_rule_5_3_2_2: {{ rhel9cis_rule_5_3_2_2 }} -rhel9cis_rule_5_3_2_3: {{ rhel9cis_rule_5_3_2_3 }} -rhel9cis_rule_5_3_2_4: {{ rhel9cis_rule_5_3_2_4 }} -rhel9cis_rule_5_3_2_5: {{ rhel9cis_rule_5_3_2_5 }} -# 5.3.3.1 Configure pam_faillock module -rhel9cis_rule_5_3_3_1_1: {{ rhel9cis_rule_5_3_3_1_1 }} -rhel9cis_rule_5_3_3_1_2: {{ rhel9cis_rule_5_3_3_1_2 }} -rhel9cis_rule_5_3_3_1_3: {{ rhel9cis_rule_5_3_3_1_3 }} -# 5.3.3.2 Configure pam_pwquality module -rhel9cis_rule_5_3_3_2_1: {{ rhel9cis_rule_5_3_3_2_1 }} -rhel9cis_rule_5_3_3_2_2: {{ rhel9cis_rule_5_3_3_2_2 }} -rhel9cis_rule_5_3_3_2_3: {{ rhel9cis_rule_5_3_3_2_3 }} -rhel9cis_rule_5_3_3_2_4: {{ rhel9cis_rule_5_3_3_2_4 }} -rhel9cis_rule_5_3_3_2_5: {{ rhel9cis_rule_5_3_3_2_5 }} -rhel9cis_rule_5_3_3_2_6: {{ rhel9cis_rule_5_3_3_2_6 }} -rhel9cis_rule_5_3_3_2_7: {{ rhel9cis_rule_5_3_3_2_7 }} -rhel9cis_rule_5_3_3_2_8: {{ rhel9cis_rule_5_3_3_2_8 }} -# 5.3.3.3 Configure pam_pwhistory module -# This are added as part of 5.3.2.4 using jinja2 template -rhel9cis_rule_5_3_3_3_1: {{ rhel9cis_rule_5_3_3_3_1 }} -rhel9cis_rule_5_3_3_3_2: {{ rhel9cis_rule_5_3_3_3_2 }} -rhel9cis_rule_5_3_3_3_3: {{ rhel9cis_rule_5_3_3_3_3 }} -# 5.3.3.4 Configure pam_unix module -rhel9cis_rule_5_3_3_4_1: {{ rhel9cis_rule_5_3_3_4_1 }} -rhel9cis_rule_5_3_3_4_2: {{ rhel9cis_rule_5_3_3_4_2 }} -rhel9cis_rule_5_3_3_4_3: {{ rhel9cis_rule_5_3_3_4_3 }} -rhel9cis_rule_5_3_3_4_4: {{ rhel9cis_rule_5_3_3_4_4 }} -# 5.4 User Accounts and Environment -# 5.4.1 Configure shadow password suite parameters -rhel9cis_rule_5_4_1_1: {{ rhel9cis_rule_5_4_1_1 }} -rhel9cis_rule_5_4_1_2: {{ rhel9cis_rule_5_4_1_2 }} -rhel9cis_rule_5_4_1_3: {{ rhel9cis_rule_5_4_1_3 }} -rhel9cis_rule_5_4_1_4: {{ rhel9cis_rule_5_4_1_4 }} -rhel9cis_rule_5_4_1_5: {{ rhel9cis_rule_5_4_1_5 }} -rhel9cis_rule_5_4_1_6: {{ rhel9cis_rule_5_4_1_6 }} -# 5.4.2 Configure root and system accounts and environment -rhel9cis_rule_5_4_2_1: {{ rhel9cis_rule_5_4_2_1 }} -rhel9cis_rule_5_4_2_2: {{ rhel9cis_rule_5_4_2_2 }} -rhel9cis_rule_5_4_2_3: {{ rhel9cis_rule_5_4_2_3 }} -rhel9cis_rule_5_4_2_4: {{ rhel9cis_rule_5_4_2_4 }} -rhel9cis_rule_5_4_2_5: {{ rhel9cis_rule_5_4_2_5 }} -rhel9cis_rule_5_4_2_6: {{ rhel9cis_rule_5_4_2_6 }} -rhel9cis_rule_5_4_2_7: {{ rhel9cis_rule_5_4_2_7 }} -rhel9cis_rule_5_4_2_8: {{ rhel9cis_rule_5_4_2_8 }} -# 5.4.2 Configure user default environment -rhel9cis_rule_5_4_3_1: {{ rhel9cis_rule_5_4_3_1 }} -rhel9cis_rule_5_4_3_2: {{ rhel9cis_rule_5_4_3_2 }} -rhel9cis_rule_5_4_3_3: {{ rhel9cis_rule_5_4_3_3 }} +rhel9cis_rule_5_2_8: {{ rhel9cis_rule_5_2_8 }} +rhel9cis_rule_5_2_9: {{ rhel9cis_rule_5_2_9 }} +rhel9cis_rule_5_2_10: {{ rhel9cis_rule_5_2_10 }} +rhel9cis_rule_5_2_11: {{ rhel9cis_rule_5_2_11 }} +rhel9cis_rule_5_2_12: {{ rhel9cis_rule_5_2_12 }} +rhel9cis_rule_5_2_13: {{ rhel9cis_rule_5_2_13 }} +rhel9cis_rule_5_2_14: {{ rhel9cis_rule_5_2_14 }} +rhel9cis_rule_5_2_15: {{ rhel9cis_rule_5_2_15 }} +rhel9cis_rule_5_2_16: {{ rhel9cis_rule_5_2_16 }} +rhel9cis_rule_5_2_17: {{ rhel9cis_rule_5_2_17 }} +rhel9cis_rule_5_2_18: {{ rhel9cis_rule_5_2_18 }} +rhel9cis_rule_5_2_19: {{ rhel9cis_rule_5_2_19 }} +rhel9cis_rule_5_2_20: {{ rhel9cis_rule_5_2_20 }} +# 5.3 Configure privilege escalation +rhel9cis_rule_5_3_1: {{ rhel9cis_rule_5_3_1 }} +rhel9cis_rule_5_3_2: {{ rhel9cis_rule_5_3_2 }} +rhel9cis_rule_5_3_3: {{ rhel9cis_rule_5_3_3 }} +rhel9cis_rule_5_3_4: {{ rhel9cis_rule_5_3_4 }} +rhel9cis_rule_5_3_5: {{ rhel9cis_rule_5_3_5 }} +rhel9cis_rule_5_3_6: {{ rhel9cis_rule_5_3_6 }} +rhel9cis_rule_5_3_7: {{ rhel9cis_rule_5_3_7 }} -# Section 6 Logging and Auditing -## 6.1 Configure Integrity Checking +# 5.4 Configure authselect + +rhel9cis_rule_5_4_1: {{ rhel9cis_rule_5_4_1 }} +rhel9cis_rule_5_4_2: {{ rhel9cis_rule_5_4_2 }} + +# 5.5 Configure PAM +rhel9cis_rule_5_5_1: {{ rhel9cis_rule_5_5_1 }} +rhel9cis_rule_5_5_2: {{ rhel9cis_rule_5_5_2 }} +rhel9cis_rule_5_5_3: {{ rhel9cis_rule_5_5_3 }} +rhel9cis_rule_5_5_4: {{ rhel9cis_rule_5_5_4 }} + +# 5.6 User Accounts and Environment +# 5.6.1 Set Shadow Password Suite Parameters +rhel9cis_rule_5_6_1_1: {{ rhel9cis_rule_5_6_1_1 }} +rhel9cis_rule_5_6_1_2: {{ rhel9cis_rule_5_6_1_2 }} +rhel9cis_rule_5_6_1_3: {{ rhel9cis_rule_5_6_1_3 }} +rhel9cis_rule_5_6_1_4: {{ rhel9cis_rule_5_6_1_4 }} +rhel9cis_rule_5_6_1_5: {{ rhel9cis_rule_5_6_1_5 }} +rhel9cis_rule_5_6_2: {{ rhel9cis_rule_5_6_2 }} +rhel9cis_rule_5_6_3: {{ rhel9cis_rule_5_6_3 }} +rhel9cis_rule_5_6_4: {{ rhel9cis_rule_5_6_4 }} +rhel9cis_rule_5_6_5: {{ rhel9cis_rule_5_6_5 }} +rhel9cis_rule_5_6_6: {{ rhel9cis_rule_5_6_6 }} + +# Section 6 +# 6 System Maintenance +# 6.1 System File Permissions rhel9cis_rule_6_1_1: {{ rhel9cis_rule_6_1_1 }} rhel9cis_rule_6_1_2: {{ rhel9cis_rule_6_1_2 }} rhel9cis_rule_6_1_3: {{ rhel9cis_rule_6_1_3 }} -## 6.2.1 Configure systemd-journald service -rhel9cis_rule_6_2_1_1: {{ rhel9cis_rule_6_2_1_1 }} -rhel9cis_rule_6_2_1_2: {{ rhel9cis_rule_6_2_1_2 }} -rhel9cis_rule_6_2_1_3: {{ rhel9cis_rule_6_2_1_3 }} -rhel9cis_rule_6_2_1_4: {{ rhel9cis_rule_6_2_1_4 }} -## 6.2.2.x Configure journald -rhel9cis_rule_6_2_2_1_1: {{ rhel9cis_rule_6_2_2_1_1 }} -rhel9cis_rule_6_2_2_1_2: {{ rhel9cis_rule_6_2_2_1_2 }} -rhel9cis_rule_6_2_2_1_3: {{ rhel9cis_rule_6_2_2_1_3 }} -rhel9cis_rule_6_2_2_1_4: {{ rhel9cis_rule_6_2_2_1_4 }} -rhel9cis_rule_6_2_2_2: {{ rhel9cis_rule_6_2_2_2 }} -rhel9cis_rule_6_2_2_3: {{ rhel9cis_rule_6_2_2_3 }} -rhel9cis_rule_6_2_2_4: {{ rhel9cis_rule_6_2_2_4 }} -## 6.2.3 Configure rsyslog -rhel9cis_rule_6_2_3_1: {{ rhel9cis_rule_6_2_3_1 }} -rhel9cis_rule_6_2_3_2: {{ rhel9cis_rule_6_2_3_2 }} -rhel9cis_rule_6_2_3_3: {{ rhel9cis_rule_6_2_3_3 }} -rhel9cis_rule_6_2_3_4: {{ rhel9cis_rule_6_2_3_4 }} -rhel9cis_rule_6_2_3_5: {{ rhel9cis_rule_6_2_3_5 }} -rhel9cis_rule_6_2_3_6: {{ rhel9cis_rule_6_2_3_6 }} -rhel9cis_rule_6_2_3_7: {{ rhel9cis_rule_6_2_3_7 }} -rhel9cis_rule_6_2_3_8: {{ rhel9cis_rule_6_2_3_8 }} -## 6.2.4 Configure Logfiles -rhel9cis_rule_6_2_4_1: {{ rhel9cis_rule_6_2_4_1 }} -## 6.3 Configure Auditing -## 6.3.1 Configure auditd Service -rhel9cis_rule_6_3_1_1: {{ rhel9cis_rule_6_3_1_1 }} -rhel9cis_rule_6_3_1_2: {{ rhel9cis_rule_6_3_1_2 }} -rhel9cis_rule_6_3_1_3: {{ rhel9cis_rule_6_3_1_3 }} -rhel9cis_rule_6_3_1_4: {{ rhel9cis_rule_6_3_1_4 }} -## 6.3.2 Configure Data Retention -rhel9cis_rule_6_3_2_1: {{ rhel9cis_rule_6_3_2_1 }} -rhel9cis_rule_6_3_2_2: {{ rhel9cis_rule_6_3_2_2 }} -rhel9cis_rule_6_3_2_3: {{ rhel9cis_rule_6_3_2_3 }} -rhel9cis_rule_6_3_2_4: {{ rhel9cis_rule_6_3_2_4 }} -## 6.3.3 Configure auditd Rules -rhel9cis_rule_6_3_3_1: {{ rhel9cis_rule_6_3_3_1 }} -rhel9cis_rule_6_3_3_2: {{ rhel9cis_rule_6_3_3_2 }} -rhel9cis_rule_6_3_3_3: {{ rhel9cis_rule_6_3_3_3 }} -rhel9cis_rule_6_3_3_4: {{ rhel9cis_rule_6_3_3_4 }} -rhel9cis_rule_6_3_3_5: {{ rhel9cis_rule_6_3_3_5 }} -rhel9cis_rule_6_3_3_6: {{ rhel9cis_rule_6_3_3_6 }} -rhel9cis_rule_6_3_3_7: {{ rhel9cis_rule_6_3_3_7 }} -rhel9cis_rule_6_3_3_8: {{ rhel9cis_rule_6_3_3_8 }} -rhel9cis_rule_6_3_3_9: {{ rhel9cis_rule_6_3_3_9 }} -rhel9cis_rule_6_3_3_10: {{ rhel9cis_rule_6_3_3_10 }} -rhel9cis_rule_6_3_3_11: {{ rhel9cis_rule_6_3_3_11 }} -rhel9cis_rule_6_3_3_12: {{ rhel9cis_rule_6_3_3_12 }} -rhel9cis_rule_6_3_3_13: {{ rhel9cis_rule_6_3_3_13 }} -rhel9cis_rule_6_3_3_14: {{ rhel9cis_rule_6_3_3_14 }} -rhel9cis_rule_6_3_3_15: {{ rhel9cis_rule_6_3_3_15 }} -rhel9cis_rule_6_3_3_16: {{ rhel9cis_rule_6_3_3_16 }} -rhel9cis_rule_6_3_3_17: {{ rhel9cis_rule_6_3_3_17 }} -rhel9cis_rule_6_3_3_18: {{ rhel9cis_rule_6_3_3_18 }} -rhel9cis_rule_6_3_3_19: {{ rhel9cis_rule_6_3_3_19 }} -rhel9cis_rule_6_3_3_20: {{ rhel9cis_rule_6_3_3_20 }} -rhel9cis_rule_6_3_3_21: {{ rhel9cis_rule_6_3_3_21 }} -## 6.3.4 Configure auditd File Access -rhel9cis_rule_6_3_4_1: {{ rhel9cis_rule_6_3_4_1 }} -rhel9cis_rule_6_3_4_2: {{ rhel9cis_rule_6_3_4_2 }} -rhel9cis_rule_6_3_4_3: {{ rhel9cis_rule_6_3_4_3 }} -rhel9cis_rule_6_3_4_4: {{ rhel9cis_rule_6_3_4_4 }} -rhel9cis_rule_6_3_4_5: {{ rhel9cis_rule_6_3_4_5 }} -rhel9cis_rule_6_3_4_6: {{ rhel9cis_rule_6_3_4_6 }} -rhel9cis_rule_6_3_4_7: {{ rhel9cis_rule_6_3_4_7 }} -rhel9cis_rule_6_3_4_8: {{ rhel9cis_rule_6_3_4_8 }} -rhel9cis_rule_6_3_4_9: {{ rhel9cis_rule_6_3_4_9 }} -rhel9cis_rule_6_3_4_10: {{ rhel9cis_rule_6_3_4_10 }} +rhel9cis_rule_6_1_4: {{ rhel9cis_rule_6_1_4 }} +rhel9cis_rule_6_1_5: {{ rhel9cis_rule_6_1_5 }} +rhel9cis_rule_6_1_6: {{ rhel9cis_rule_6_1_6 }} +rhel9cis_rule_6_1_7: {{ rhel9cis_rule_6_1_7 }} +rhel9cis_rule_6_1_8: {{ rhel9cis_rule_6_1_8 }} +rhel9cis_rule_6_1_9: {{ rhel9cis_rule_6_1_9 }} +rhel9cis_rule_6_1_10: {{ rhel9cis_rule_6_1_10 }} +rhel9cis_rule_6_1_11: {{ rhel9cis_rule_6_1_11 }} +rhel9cis_rule_6_1_12: {{ rhel9cis_rule_6_1_12 }} +rhel9cis_rule_6_1_13: {{ rhel9cis_rule_6_1_13 }} +rhel9cis_rule_6_1_14: {{ rhel9cis_rule_6_1_14 }} +rhel9cis_rule_6_1_15: {{ rhel9cis_rule_6_1_15 }} -# Section 7 System Maintenance -## 7.1 System File Permissions -rhel9cis_rule_7_1_1: {{ rhel9cis_rule_7_1_1 }} -rhel9cis_rule_7_1_2: {{ rhel9cis_rule_7_1_2 }} -rhel9cis_rule_7_1_3: {{ rhel9cis_rule_7_1_3 }} -rhel9cis_rule_7_1_4: {{ rhel9cis_rule_7_1_4 }} -rhel9cis_rule_7_1_5: {{ rhel9cis_rule_7_1_5 }} -rhel9cis_rule_7_1_6: {{ rhel9cis_rule_7_1_6 }} -rhel9cis_rule_7_1_7: {{ rhel9cis_rule_7_1_7 }} -rhel9cis_rule_7_1_8: {{ rhel9cis_rule_7_1_8 }} -rhel9cis_rule_7_1_9: {{ rhel9cis_rule_7_1_9 }} -rhel9cis_rule_7_1_10: {{ rhel9cis_rule_7_1_10 }} -rhel9cis_rule_7_1_11: {{ rhel9cis_rule_7_1_11 }} -rhel9cis_rule_7_1_12: {{ rhel9cis_rule_7_1_12 }} -rhel9cis_rule_7_1_13: {{ rhel9cis_rule_7_1_13 }} -## 7.2 Local User and Group Settings -rhel9cis_rule_7_2_1: {{ rhel9cis_rule_7_2_1 }} -rhel9cis_rule_7_2_2: {{ rhel9cis_rule_7_2_2 }} -rhel9cis_rule_7_2_3: {{ rhel9cis_rule_7_2_3 }} -rhel9cis_rule_7_2_4: {{ rhel9cis_rule_7_2_4 }} -rhel9cis_rule_7_2_5: {{ rhel9cis_rule_7_2_5 }} -rhel9cis_rule_7_2_6: {{ rhel9cis_rule_7_2_6 }} -rhel9cis_rule_7_2_7: {{ rhel9cis_rule_7_2_7 }} -rhel9cis_rule_7_2_8: {{ rhel9cis_rule_7_2_8 }} -rhel9cis_rule_7_2_9: {{ rhel9cis_rule_7_2_9 }} +# 6.2 User and Group Settings +rhel9cis_rule_6_2_1: {{ rhel9cis_rule_6_2_1 }} +rhel9cis_rule_6_2_2: {{ rhel9cis_rule_6_2_2 }} +rhel9cis_rule_6_2_3: {{ rhel9cis_rule_6_2_3 }} +rhel9cis_rule_6_2_4: {{ rhel9cis_rule_6_2_4 }} +rhel9cis_rule_6_2_5: {{ rhel9cis_rule_6_2_5 }} +rhel9cis_rule_6_2_6: {{ rhel9cis_rule_6_2_6 }} +rhel9cis_rule_6_2_7: {{ rhel9cis_rule_6_2_7 }} +rhel9cis_rule_6_2_8: {{ rhel9cis_rule_6_2_8 }} +rhel9cis_rule_6_2_9: {{ rhel9cis_rule_6_2_9 }} +rhel9cis_rule_6_2_10: {{ rhel9cis_rule_6_2_10 }} +rhel9cis_rule_6_2_11: {{ rhel9cis_rule_6_2_11 }} +rhel9cis_rule_6_2_12: {{ rhel9cis_rule_6_2_12 }} +rhel9cis_rule_6_2_13: {{ rhel9cis_rule_6_2_13 }} +rhel9cis_rule_6_2_14: {{ rhel9cis_rule_6_2_14 }} +rhel9cis_rule_6_2_15: {{ rhel9cis_rule_6_2_15 }} +rhel9cis_rule_6_2_16: {{ rhel9cis_rule_6_2_16 }} -## Section 1 vars +############ -## Control 1.4.1 -# This variable governs whether a bootloader password should be set in '/boot/grub2/user.cfg' file. -rhel9cis_set_boot_pass: {{ rhel9cis_set_boot_pass }} +# Section 1 -## Controls: -# - 1.7.1 - Ensure message of the day is configured properly -# - 1.7.2 - Ensure local login warning banner is configured properly -# - 1.7.3 - Ensure remote login warning banner is configured properly -# This variable stores the content for the Warning Banner(relevant for issue, issue.net, motd). +# AIDE +rhel9cis_config_aide: {{ rhel9cis_config_aide }} + +# Whether or not to run tasks related to auditing/patching the desktop environment +rhel9cis_gui: {{ rhel9cis_gui }} + +# Warning Banner Content (issue, issue.net, motd) rhel9cis_warning_banner: {{ rhel9cis_warning_banner }} # End Banner -## Control 1.8.x - Settings for GDM -## 1.8 GDM graphical interface -rhel9cis_gui: {{ rhel9cis_gui }} +# aide setup via - cron, timer +rhel9_aide_scan: cron -# This variable specifies the GNOME configuration database file to which configurations are written. -# (See "https://help.gnome.org/admin/system-admin-guide/stable/dconf-keyfiles.html.en") -# The default database is 'local'. +# 1.8 Gnome Desktop rhel9cis_dconf_db_name: {{ rhel9cis_dconf_db_name }} +rhel9cis_screensaver_idle_delay: {{ rhel9cis_screensaver_idle_delay }} # Set max value for idle-delay in seconds (between 1 and 900) +rhel9cis_screensaver_lock_delay: {{ rhel9cis_screensaver_lock_delay }} # Set max value for lock-delay in seconds (between 0 and 5) - -## Section 2. Services - -# Service configuration -# Options are -# Service -# - false - removes package -# - true - leaves package installed -# Mask -# - false - leaves service in current status -# - true - sets service name to masked -# -# Setting both Service and Mask to false will remove the package if exists -rhel9cis_autofs_services: {{ rhel9cis_autofs_services }} -rhel9cis_autofs_mask: {{ rhel9cis_autofs_mask }} +# Section 2 +## 2.2 Special Purposes +# Set to 'true' if X Windows is needed in your environment +rhel9cis_xwindows_required: false +### Service configuration booleans set true to keep service rhel9cis_avahi_server: {{ rhel9cis_avahi_server }} -rhel9cis_avahi_mask: {{ rhel9cis_avahi_mask }} +rhel9cis_cups_server: {{ rhel9cis_cups_server }} rhel9cis_dhcp_server: {{ rhel9cis_dhcp_server }} -rhel9cis_dhcp_mask: {{ rhel9cis_dhcp_mask }} rhel9cis_dns_server: {{ rhel9cis_dns_server }} -rhel9cis_dns_mask: {{ rhel9cis_dns_mask }} rhel9cis_dnsmasq_server: {{ rhel9cis_dnsmasq_server }} -rhel9cis_dnsmasq_mask: {{ rhel9cis_dnsmasq_mask }} -rhel9cis_samba_server: {{ rhel9cis_samba_server }} -rhel9cis_samba_mask: {{ rhel9cis_samba_mask }} -rhel9cis_ftp_server: {{ rhel9cis_ftp_server }} -rhel9cis_ftp_mask: {{ rhel9cis_ftp_mask }} -rhel9cis_message_server: {{ rhel9cis_message_server }} # This is for messaging dovecot and cyrus-imap -rhel9cis_message_mask: {{ rhel9cis_message_mask }} -rhel9cis_nfs_server: {{ rhel9cis_nfs_server }} -rhel9cis_nfs_mask: {{ rhel9cis_nfs_mask }} -rhel9cis_nis_server: {{ rhel9cis_nis_server }} # set to mask if nis client required -rhel9cis_nis_mask: {{ rhel9cis_nis_mask }} -rhel9cis_print_server: {{ rhel9cis_print_server }} # replaces cups -rhel9cis_print_mask: {{ rhel9cis_print_mask }} -rhel9cis_rpc_server: {{ rhel9cis_rpc_server }} -rhel9cis_rpc_mask: {{ rhel9cis_rpc_mask }} -rhel9cis_rsync_server: {{ rhel9cis_rsync_server }} -rhel9cis_rsync_mask: {{ rhel9cis_rsync_mask }} -rhel9cis_snmp_server: {{ rhel9cis_snmp_server }} -rhel9cis_snmp_mask: {{ rhel9cis_snmp_mask }} -rhel9cis_telnet_server: {{ rhel9cis_telnet_server }} -rhel9cis_telnet_mask: {{ rhel9cis_telnet_mask }} +rhel9cis_vsftpd_server: {{ rhel9cis_vsftpd_server }} rhel9cis_tftp_server: {{ rhel9cis_tftp_server }} -rhel9cis_tftp_mask: {{ rhel9cis_tftp_mask }} -rhel9cis_squid_server: {{ rhel9cis_squid_server }} -rhel9cis_squid_mask: {{ rhel9cis_squid_mask }} rhel9cis_httpd_server: {{ rhel9cis_httpd_server }} -rhel9cis_httpd_mask: {{ rhel9cis_httpd_mask }} rhel9cis_nginx_server: {{ rhel9cis_nginx_server }} -rhel9cis_nginx_mask: {{ rhel9cis_nginx_mask }} -rhel9cis_xinetd_server: {{ rhel9cis_xinetd_server }} -rhel9cis_xinetd_mask: {{ rhel9cis_xinetd_mask }} -rhel9cis_xwindow_server: {{ rhel9cis_xwindow_server }} # will remove mask not an option +rhel9cis_dovecot_server: {{ rhel9cis_dovecot_server }} +rhel9cis_imap_server: {{ rhel9cis_imap_server }} +rhel9cis_samba_server: {{ rhel9cis_samba_server }} +rhel9cis_squid_server: {{ rhel9cis_squid_server }} +rhel9cis_snmp_server: {{ rhel9cis_snmp_server }} +rhel9cis_telnet_server: {{ rhel9cis_telnet_server }} rhel9cis_is_mail_server: {{ rhel9cis_is_mail_server }} -## Section 2.3 Service clients +# Note the options +# Packages are used for client services and Server- only remove if you dont use the client service +# +rhel9cis_use_nfs_server: {{ rhel9cis_use_nfs_server }} +rhel9cis_use_nfs_service: {{ rhel9cis_use_nfs_service }} +rhel9cis_use_rpc_server: {{ rhel9cis_use_rpc_server }} +rhel9cis_use_rpc_service: {{ rhel9cis_use_rpc_service }} +rhel9cis_use_rsync_server: {{ rhel9cis_use_rsync_server }} +rhel9cis_use_rsync_service: {{ rhel9cis_use_rsync_service }} -rhel9cis_ftp_client: {{ rhel9cis_ftp_client }} -rhel9cis_openldap_clients_required: {{ rhel9cis_openldap_clients_required }} -rhel9cis_ypbind_required: {{ rhel9cis_ypbind_required }} # Same package as NIS server +#### 2.3 Service clients rhel9cis_telnet_required: {{ rhel9cis_telnet_required }} +rhel9cis_openldap_clients_required: {{ rhel9cis_openldap_clients_required }} rhel9cis_tftp_client: {{ rhel9cis_tftp_client }} +rhel9cis_ftp_client: {{ rhel9cis_ftp_client }} -## Section 3 vars -## Sysctl -# Service configuration -# Options are -# Service -# - false - removes package -# - true - leaves package installed -# Mask -# - false - leaves service in current status -# - true - sets service name to masked -# -# Setting both Service and Mask to false will remove the package if exists -# -rhel9cis_bluetooth_service: {{ rhel9cis_bluetooth_service }} -rhel9cis_bluetooth_mask: {{ rhel9cis_bluetooth_mask }} +# Section 3 -## 3.1 IPv6 requirement toggle -# This variable governs whether ipv6 is enabled or disabled. +## IPv6 required rhel9cis_ipv6_required: {{ rhel9cis_ipv6_required }} -# 3.3 System network parameters (host only OR host and router) -# This variable governs whether specific CIS rules -# concerned with acceptance and routing of packages are skipped. +## 3.2 System network parameters (host only OR host and router) rhel9cis_is_router: {{ rhel9cis_is_router }} -# Section 4 vars -### Firewall Service to install and configure - Options are: -# 1) either 'firewalld' -# 2) or 'nftables' -#### Some control allow for services to be removed or masked -#### The options are under each heading -#### absent = remove the package -#### masked = leave package if installed and mask the service +## Section 3.4 +### Firewall rhel9cis_firewall: {{ rhel9cis_firewall }} +##### firewalld +rhel9cis_default_zone: {{ rhel9cis_default_zone }} -## Section5 vars +#### nftables -## Section 5.1 - SSH +rhel9cis_nft_tables_autonewtable: {{ rhel9cis_nft_tables_autonewtable }} +rhel9cis_nft_tables_tablename: {{ rhel9cis_nft_tables_tablename }} +rhel9cis_nft_tables_autochaincreate: {{ rhel9cis_nft_tables_autochaincreate }} -## Controls: -## - 5.1.7 - Ensure SSH access is limited -# This variable, if specified, configures a list of USER name patterns, separated by spaces, to allow SSH -# access for users whose user name matches one of the patterns. This is done -# by setting the value of `AllowUsers` option in `/etc/ssh/sshd_config` file. -# If an USER@HOST format will be used, the specified user will be allowed only on that particular host. -rhel9cis_sshd_allowusers: "{% if ansible_facts.user_id != 'root' %}{{ ansible_facts.user_id }}{% elif ansible_env.SUDO_USER is defined %}{{ ansible_env.SUDO_USER }}{% endif %}" -# (String) This variable, if specified, configures a list of GROUP name patterns, separated by spaces, to allow SSH access -# for users whose primary group or supplementary group list matches one of the patterns. This is done -# by setting the value of `AllowGroups` option in `/etc/ssh/sshd_config` file. -rhel9cis_sshd_allowgroups: {{ rhel9cis_sshd_allowgroups }} +# Section 4 -# This variable, if specified, configures a list of USER name patterns, separated by spaces, to prevent SSH access -# for users whose user name matches one of the patterns. This is done -# by setting the value of `DenyUsers` option in `/etc/ssh/sshd_config` file. -# If an USER@HOST format will be used, the specified user will be restricted only on that particular host. -rhel9cis_sshd_denyusers: {{ rhel9cis_sshd_denyusers }} - -# This variable, if specified, configures a list of GROUP name patterns, separated by spaces, -# to prevent SSH access for users whose primary group or supplementary group list matches one of the patterns. This is done -# by setting the value of `DenyGroups` option in `/etc/ssh/sshd_config` file. -rhel9cis_sshd_denygroups: {{ rhel9cis_sshd_denygroups }} - -## Control 5.2.x - Ensure sudo log file exists -# By default, sudo logs through syslog(3). However, to specify a custom log file, the -# 'logfile' parameter will be used, setting it with current variable's value. -# This variable defines the path and file name of the sudo log file. -rhel9cis_sudolog_location: {{ rhel9cis_sudolog_location }} - -## Control 5.2.4 -# This will leave NOPASSWD intact for these users -rhel9cis_sudoers_exclude_nopasswd_list: - - ec2-user - - vagrant - -## Control 5.2 - Ensure access to the 'su' command is restricted -# This variable determines the name of the group of users that are allowed to use the su command. -# CIS requires that such a group be CREATED(named according to site policy) and be kept EMPTY. -rhel9cis_sugroup: {{ rhel9cis_sugroup }} - -# Control 5.3.3.2 -# Choose if using minclass or credits options -# Options are: minclass or credits -# ensure only one is selected -rhel9cis_passwd_complex_option: {{ rhel9cis_passwd_complex_option }} - -## Section 5.4.1.x: Shadow Password Suite Parameters - ## Control 5.4.1.1 - Ensure password expiration is 365 days or less - # This variable governs after how many days a password expires. - # CIS requires a value of 365 or less. -rhel9cis_pass_max_days: 365 - ## Control 5.4.1.2 - Ensure minimum days between password changes is 7 or more - # This variable specifies the minimum number of days allowed between changing - # passwords. CIS requires a value of at least 1. -rhel9cis_pass_min_days: 7 - ## Control 5.4.1.3 - Ensure password expiration warning days is 7 or more - # This variable governs, how many days before a password expires, the user will be warned. - # CIS requires a value of at least 7. -rhel9cis_pass_warn_age: 7 - -## PAM AND Authselect - -# This variable configures the name of the custom profile to be created and selected. -# To be changed from default - cis_example_profile -rhel9cis_authselect_custom_profile_name: {{ rhel9cis_authselect_custom_profile_name }} - -### Controls: -# - 5.6.2 - Ensure system accounts are secured -# - 6.2.10 - Ensure local interactive user home directories exist -# - 6.2.11 - Ensure local interactive users own their home directories -# UID settings for interactive users -# These are discovered via logins.def if set true -rhel9cis_discover_int_uid: {{ rhel9cis_discover_int_uid }} -# This variable sets the minimum number from which to search for UID -# Note that the value will be dynamically overwritten if variable `discover_int_uid` has -# been set to `true`. -min_int_uid: 1000 -### Controls: -# - Ensure local interactive user home directories exist -# - Ensure local interactive users own their home directories -# This variable sets the maximum number at which the search stops for UID -# Note that the value will be dynamically overwritten if variable `discover_int_uid` has -# been set to `true`. -max_int_uid: 65533 - -## Section6 vars - -## Control 6.1.2 AIDE schedule -# how aide scheduler runs can be one of cron or timer -rhel9cis_aide_scan: {{ rhel9cis_aide_scan }} - -# These are the crontab settings for periodical checking of the filesystem's integrity using AIDE. -# The sub-settings of this variable provide the parameters required to configure -# the cron job on the target system. -# Cron is a time-based job scheduling program in Unix OS, which allows tasks to be scheduled -# and executed automatically at a certain point in time. -rhel9cis_aide_cron: - # This variable represents the user account under which the cron job for AIDE will run. - cron_user: root - # This variable represents the path to the AIDE crontab file. - cron_file: /etc/cron.d/aide_cron - # This variable represents the actual command or script that the cron job - # will execute for running AIDE. - aide_job: '/usr/sbin/aide --check' - # These variables define the schedule for the cron job - # This variable governs the minute of the time of day when the AIDE cronjob is run. - # It must be in the range `0-59`. - aide_minute: 0 - # This variable governs the hour of the time of day when the AIDE cronjob is run. - # It must be in the range `0-23`. - aide_hour: 5 - # This variable governs the day of the month when the AIDE cronjob is run. - # `*` signifies that the job is run on all days; furthermore, specific days - # can be given in the range `1-31`; several days can be concatenated with a comma. - # The specified day(s) can must be in the range `1-31`. - aide_day: '*' - # This variable governs months when the AIDE cronjob is run. - # `*` signifies that the job is run in every month; furthermore, specific months - # can be given in the range `1-12`; several months can be concatenated with commas. - # The specified month(s) can must be in the range `1-12`. - aide_month: '*' - # This variable governs the weekdays, when the AIDE cronjob is run. - # `*` signifies that the job is run on all weekdays; furthermore, specific weekdays - # can be given in the range `0-7` (both `0` and `7` represent Sunday); several weekdays - # can be concatenated with commas. - aide_weekday: '*' -# -## Preferred method of logging -## Whether rsyslog or journald preferred method for local logging -## Control 6.2.3 | Configure rsyslog -## Control 6.2.1 | Configure journald -# This variable governs which logging service should be used, choosing between 'rsyslog'(CIS recommendation) -# or 'journald'(only one is implemented) will trigger the execution of the associated subsection, as the-best -# practices are written wholly independent of each other. -rhel9cis_syslog: {{ rhel9cis_syslog }} - -## Control 6.2.2.x & 6.2.3.x - Ensure rsyslog is not configured to receive logs from a remote client -# This variable expresses whether the system is used as a log server or not. If set to: -# - 'false', current system will act as a log CLIENT, thus it should NOT receive data from other hosts. -# - 'true', current system will act as a log SERVER, enabling centralised log management(by protecting log integrity -# from local attacks on remote clients) -rhel9cis_system_is_log_server: {{ rhel9cis_system_is_log_server }} - -## Control 6.2.3.6 - Ensure rsyslog is configured to send logs to a remote log host -# This variable governs if 'rsyslog' service should be automatically configured to forward messages to a -# remote log server. If set to 'false', the configuration of the 'omfwd' plugin, used to provide forwarding -# over UDP or TCP, will not be performed. +## Set if host is a logserver rhel9cis_remote_log_server: {{ rhel9cis_remote_log_server }} -## Control 6.2.3.6 - Ensure rsyslog is configured to send logs to a remote log host -# This variable configures the value of the 'target' parameter to be configured when enabling -# forwarding syslog messages to a remote log server, thus configuring the actual FQDN/IP address of the -# destination server. For this value to be reflected in the configuration, the variable which enables the -# automatic configuration of rsyslog forwarding must be enabled('rhel9cis_remote_log_server: {{ rhel9cis_remote_log_server }}'). +# Remote logserver settings rhel9cis_remote_log_host: {{ rhel9cis_remote_log_host }} - -## Control 6.2.3.6 - Ensure rsyslog is configured to send logs to a remote log host -# This variable configures the value of the 'port' parameter to be configured when enabling -# forwarding syslog messages to a remote log server. The default value for this destination port is 514. -# For this value to be reflected in the configuration, the variable which enables the -# automatic configuration of rsyslog forwarding must be enabled('rhel9cis_remote_log_server: {{ rhel9cis_remote_log_server }}'). rhel9cis_remote_log_port: {{ rhel9cis_remote_log_port }} - -## Control 6.2.3.6 - Ensure rsyslog is configured to send logs to a remote log host -# This variable configures the value("TCP"/"UDP") of the 'protocol' parameter to be configured when enabling -# forwarding syslog messages to a remote log server. The default value for the 'omfwd' plug-in is UDP. -# For this value to be reflected in the configuration, the variable which enables the -# automatic configuration of rsyslog forwarding must be enabled('rhel9cis_remote_log_server: {{ rhel9cis_remote_log_server }}'). rhel9cis_remote_log_protocol: {{ rhel9cis_remote_log_protocol }} - -## Control 6.2.3.6 - Ensure rsyslog is configured to send logs to a remote log host -# This variable governs how often an action is retried(value is passed to 'action.resumeRetryCount' parameter) before -# it is considered to have failed(that roughly translates to discarded messages). The default value is 0, but -# when set to "-1"(eternal), this setting would prevent rsyslog from dropping messages when retrying to connect -# if server is not responding. For this value to be reflected in the configuration, the variable which enables the -# automatic configuration of rsyslog forwarding must be enabled('rhel9cis_remote_log_server: {{ rhel9cis_remote_log_server }}'). rhel9cis_remote_log_retrycount: {{ rhel9cis_remote_log_retrycount }} - -## Control 6.2.3.6 - Ensure rsyslog is configured to send logs to a remote log host -# This variable configures the maximum number of messages that can be hold(value is passed to 'queue.size' parameter). -# For this value to be reflected in the configuration, the variable which enables the automatic configuration -# of rsyslog forwarding must be enabled('rhel9cis_remote_log_server: {{ rhel9cis_remote_log_server }}'). rhel9cis_remote_log_queuesize: {{ rhel9cis_remote_log_queuesize }} -## Control 6.2.2.1.2 - Ensure systemd-journal-remote is configured -# 'rhel9cis_journal_upload_url' is the ip address to upload the journal entries to -# URL value may specify either just the hostname or both the protocol and hostname. 'https' is the default. The port -# number may be specified after a colon (":"), otherwise 19532 will be used by default. -rhel9cis_journal_upload_url: {{ rhel9cis_journal_upload_url }} +## syslog +rhel9cis_syslog: {{ rhel9cis_syslog }} -## Control 6.2.2.1.2 - Ensure systemd-journal-remote is configured -# This variable specifies the path to the private key file used by the remote journal -# server to authenticate itself to the client. This key is used alongside the server's -# public certificate to establish secure communication. -rhel9cis_journal_upload_serverkeyfile: {{ rhel9cis_journal_upload_serverkeyfile }} +# Section 5 +# This will allow use of drop in files when CIS adopts them. +rhel9_cis_sshd_config_file: {{ rhel9_cis_sshd_config_file }} -## Control 6.2.2.1.2 - Ensure systemd-journal-remote is configured -# This variable specifies the path to the public certificate file of the remote journal -# server. This certificate is used to verify the authenticity of the remote server. -rhel9cis_journal_servercertificatefile: {{ rhel9cis_journal_servercertificatefile }} +## 5.2.4 Note the following to understand precedence and layout +rhel9cis_sshd_limited: false +rhel9cis_sshd_access: + - AllowUser + - AllowGroup + - DenyUser + - DenyGroup -## Control 6.2.2.1.2 - Ensure systemd-journal-remote is configured -# This variable specifies the path to a file containing one or more public certificates -# of certificate authorities (CAs) that the client trusts. These trusted certificates are used -# to validate the authenticity of the remote server's certificate. -rhel9cis_journal_trustedcertificatefile: {{ rhel9cis_journal_trustedcertificatefile }} +## 5.3.2 & 5.4.2 Enable automation to select custom profile options, using the settings above +rhel9cis_authselect_custom_profile_select: {{ rhel9cis_authselect_custom_profile_select }} -# Section 7 Vars +## 5.3.2 Authselect select false if using AD or RHEL ID mgmt +rhel9cis_authselect: + custom_profile_name: {{ rhel9cis_authselect['custom_profile_name'] }} + default_file_to_copy: {{ rhel9cis_authselect['default_file_to_copy'] }} -# 7.1.12 Ensure no files or directories without an owner and a group exist -rhel9cis_exclude_unowned_search_path: \( ! -path "/run/user/*" -a ! -path "/proc/*" -a ! -path "*/containerd/*" -a ! -path "*/kubelet/pods/*" -a ! -path "*/kubelet/plugins/*" -a ! -path "/sys/fs/cgroup/memory/*" -a ! -path "/var/*/private/*" \) + +## 5.4.1 Enable automation to create custom profile settings, using the setings above +rhel9cis_authselect_custom_profile_create: {{ rhel9cis_authselect_custom_profile_create }} + +# 5.5.1 +## PAM +rhel9cis_pam_password: + minlen: {{ rhel9cis_pam_password['minlen'] }} + minclass: {{ rhel9cis_pam_password['minclass'] }} +rhel9cis_pam_passwd_retry: "3" + +## 5.5.3 choose one of below +rhel9cis_pwhistory_so: "14" +rhel9cis_passwd_remember: "5" + +## 5.6.x login.defs password settings +rhel9cis_pass: + max_days: {{ rhel9cis_pass['max_days'] }} + min_days: {{ rhel9cis_pass['min_days'] }} + warn_age: {{ rhel9cis_pass['warn_age'] }} + +## 5.3.7 set sugroup if differs from wheel +rhel9cis_sugroup: {{ rhel9cis_sugroup }} diff --git a/templates/audit/98_auditd_exception.rules.j2 b/templates/audit/98_auditd_exception.rules.j2 index 70ebd03..2f76269 100644 --- a/templates/audit/98_auditd_exception.rules.j2 +++ b/templates/audit/98_auditd_exception.rules.j2 @@ -1,10 +1,10 @@ ## Ansible controlled file -# Added as part of ansible-lockdown CIS baseline -# provided by Mindpoint Group - A Tyto Athene Company +# Added as part of ansible-lockdown CIS baseline +# provided by MindPointGroup LLC ### YOUR CHANGES WILL BE LOST! # This file contains users whose actions are not logged by auditd -{% if rhel9cis_allow_auditd_uid_user_exclusions %} +{% if rhel9cis_allow_auditd_uid_user_exclusions %} {% for user in rhel9cis_auditd_uid_exclude %} -a never,user -F uid!={{ user }} -F auid!={{ user }} {% endfor %} diff --git a/templates/audit/99_auditd.rules.j2 b/templates/audit/99_auditd.rules.j2 index c3c2b6c..c48782c 100644 --- a/templates/audit/99_auditd.rules.j2 +++ b/templates/audit/99_auditd.rules.j2 @@ -1,133 +1,98 @@ ## Ansible controlled file -# Added as part of ansible-lockdown CIS baseline -# provided by Mindpoint Group - A Tyto Athene Company +# Added as part of ansible-lockdown CIS baseline +# provided by MindPointGroup LLC ### YOUR CHANGES WILL BE LOST! # This template will set all of the auditd configurations via a handler in the role in one task instead of individually -{% if rhel9cis_rule_6_3_3_1 %} +{% if rhel9cis_rule_4_1_3_1 %} -w /etc/sudoers -p wa -k scope -w /etc/sudoers.d -p wa -k scope {% endif %} -{% if rhel9cis_rule_6_3_3_2 %} -{% set syscalls = ["execve"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b64 -C euid!=uid -F auid!=unset -S {{ arch_syscalls|join(',') }} -k user_emulation --a always,exit -F arch=b32 -C euid!=uid -F auid!=unset -S {{ arch_syscalls|join(',') }} -k user_emulation +{% if rhel9cis_rule_4_1_3_2 %} +-a always,exit -F arch=b64 -C euid!=uid -F auid!=unset -S execve -k user_emulation +-a always,exit -F arch=b32 -C euid!=uid -F auid!=unset -S execve -k user_emulation {% endif %} -{% if rhel9cis_rule_6_3_3_3 %} +{% if rhel9cis_rule_4_1_3_3 %} -w {{ rhel9cis_sudolog_location }} -p wa -k sudo_log_file {% endif %} -{% if rhel9cis_rule_6_3_3_4 %} -{% set syscalls = ["adjtimex","settimeofday"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -k time-change --a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -k time-change -{% set syscalls = ["clock_settime"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F a0=0x0 -k time-change --a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F a0=0x0 -k time-change +{% if rhel9cis_rule_4_1_3_4 %} +-a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k time-change +-a always,exit -F arch=b32 -S adjtimex,settimeofday,clock_settime -k time-change -w /etc/localtime -p wa -k time-change {% endif %} -{% if rhel9cis_rule_6_3_3_5 %} -{% set syscalls = ["sethostname","setdomainname"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -k system-locale --a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -k system-locale +{% if rhel9cis_rule_4_1_3_5 %} +-a always,exit -F arch=b64 -S sethostname,setdomainname -F key=system-locale +-a always,exit -F arch=b32 -S sethostname,setdomainname -F key=system-locale -w /etc/issue -p wa -k system-locale -w /etc/issue.net -p wa -k system-locale -w /etc/hosts -p wa -k system-locale --w /etc/hostname -p wa -k system-locale -w /etc/sysconfig/network -p wa -k system-locale -w /etc/sysconfig/network-scripts -p wa -k system-locale --w /etc/NetworkManager -p wa -k system-locale {% endif %} -{% if rhel9cis_rule_6_3_3_6 %} -{% for proc in discovered_priv_procs.stdout_lines -%} --a always,exit -F path={{ proc }} -F perm=x -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k privileged +{% if rhel9cis_rule_4_1_3_6 %} +{% for proc in priv_procs.stdout_lines -%} +-a always,exit -F path={{ proc }} -F perm=x -F auid>={{ min_int_uid }} -F auid!=unset -k privileged {% endfor %} {% endif %} -{% if rhel9cis_rule_6_3_3_7 %} -{% set syscalls = ["creat","open","openat","truncate","ftruncate"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F exit=-EACCES -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k access --a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F exit=-EPERM -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k access --a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F exit=-EACCES -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k access --a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F exit=-EPERM -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k access +{% if rhel9cis_rule_4_1_3_7 %} +-a always,exit -F arch=b64 -S creat,open,openat,truncate,ftruncate -F exit=-EACCES -F auid>={{ min_int_uid }} -F auid!=unset -k access +-a always,exit -F arch=b64 -S creat,open,openat,truncate,ftruncate -F exit=-EPERM -F auid>={{ min_int_uid }} -F auid!=unset -k access +-a always,exit -F arch=b32 -S creat,open,openat,truncate,ftruncate -F exit=-EACCES -F auid>={{ min_int_uid }} -F auid!=unset -k access +-a always,exit -F arch=b32 -S creat,open,openat,truncate,ftruncate -F exit=-EPERM -F auid>={{ min_int_uid }} -F auid!=unset -k access {% endif %} -{% if rhel9cis_rule_6_3_3_8 %} +{% if rhel9cis_rule_4_1_3_8 %} -w /etc/group -p wa -k identity -w /etc/passwd -p wa -k identity -w /etc/gshadow -p wa -k identity -w /etc/shadow -p wa -k identity -w /etc/security/opasswd -p wa -k identity --w /etc/nsswitch.conf -p wa -k identity --w /etc/pam.conf -p wa -k identity --w /etc/pam.d -p wa -k identity {% endif %} -{% if rhel9cis_rule_6_3_3_9 %} -{% set syscalls = ["chmod","fchmod","fchmodat"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_mod -{% set syscalls = ["chown","fchown","lchown","fchownat"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_mod -{% set syscalls = ["setxattr","lsetxattr","fsetxattr","removexattr","lremovexattr","fremovexattr"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_mod -{% set syscalls = ["chmod","fchmod","fchmodat"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_mod -{% set syscalls = ["chown","fchown","lchown","fchownat"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_mod -{% set syscalls = ["setxattr","lsetxattr","fsetxattr","removexattr","lremovexattr","fremovexattr"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_mod +{% if rhel9cis_rule_4_1_3_9 %} +-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>={{ min_int_uid }} -F auid!=unset -F key=perm_mod +-a always,exit -F arch=b64 -S chown,fchown,lchown,fchownat -F auid>={{ min_int_uid }} -F auid!=unset -F key=perm_mod +-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>={{ min_int_uid }} -F auid!=unset -F key=perm_mod +-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F auid>={{ min_int_uid }} -F auid!=unset -F key=perm_mod +-a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>={{ min_int_uid }} -F auid!=unset -F key=perm_mod +-a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>={{ min_int_uid }} -F auid!=unset -F key=perm_mod {% endif %} -{% if rhel9cis_rule_6_3_3_10 %} -{% set syscalls = ["mount"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k mounts --a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k mounts +{% if rhel9cis_rule_4_1_3_10 %} +-a always,exit -F arch=b32 -S mount -F auid>={{ min_int_uid }} -F auid!=unset -k mounts +-a always,exit -F arch=b64 -S mount -F auid>={{ min_int_uid }} -F auid!=unset -k mounts {% endif %} -{% if rhel9cis_rule_6_3_3_11 %} +{% if rhel9cis_rule_4_1_3_11 %} -w /var/run/utmp -p wa -k session -w /var/log/wtmp -p wa -k session -w /var/log/btmp -p wa -k session {% endif %} -{% if rhel9cis_rule_6_3_3_12 %} +{% if rhel9cis_rule_4_1_3_12 %} -w /var/log/lastlog -p wa -k logins -w /var/run/faillock -p wa -k logins {% endif %} -{% if rhel9cis_rule_6_3_3_13 %} -{% set syscalls = ["unlink","unlinkat","rename","renameat"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k delete --a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k delete +{% if rhel9cis_rule_4_1_3_13 %} +-a always,exit -F arch=b64 -S rename,unlink,unlinkat,renameat -F auid>={{ min_int_uid }} -F auid!=unset -F key=delete +-a always,exit -F arch=b32 -S rename,unlink,unlinkat,renameat -F auid>={{ min_int_uid }} -F auid!=unset -F key=delete {% endif %} -{% if rhel9cis_rule_6_3_3_14 %} +{% if rhel9cis_rule_4_1_3_14 %} -w /etc/selinux -p wa -k MAC-policy -w /usr/share/selinux -p wa -k MAC-policy {% endif %} -{% if rhel9cis_rule_6_3_3_15 %} --a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_chng +{% if rhel9cis_rule_4_1_3_15 %} +-a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>={{ min_int_uid }} -F auid!=unset -k perm_chng {% endif %} -{% if rhel9cis_rule_6_3_3_16 %} --a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_chng +{% if rhel9cis_rule_4_1_3_16 %} +-a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>={{ min_int_uid }} -F auid!=unset -k perm_chng {% endif %} -{% if rhel9cis_rule_6_3_3_17 %} --a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_chng +{% if rhel9cis_rule_4_1_3_17 %} +-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>={{ min_int_uid }} -F auid!=unset -k priv_cmd {% endif %} -{% if rhel9cis_rule_6_3_3_18 %} --a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k usermod +{% if rhel9cis_rule_4_1_3_18 %} +-a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>={{ min_int_uid }} -F auid!=unset -k usermod {% endif %} -{% if rhel9cis_rule_6_3_3_19 %} --a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k kernel_modules -{% set syscalls = ["init_module","finit_module","delete_module","create_module","query_module"] %} -{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %} --a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k kernel_modules +{% if rhel9cis_rule_4_1_3_19 %} +-a always,exit -F arch=b64 -S init_module,finit_module,delete_module,create_module,query_module -F auid>={{ min_int_uid }} -F auid!=unset -k kernel_modules +-a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>={{ min_int_uid }} -F auid!=unset -k kernel_modules {% endif %} -{% if rhel9cis_rule_6_3_3_20 %} +{% if rhel9cis_rule_4_1_3_20 %} -e 2 {% endif %} diff --git a/templates/etc/ansible/compliance_facts.j2 b/templates/etc/ansible/compliance_facts.j2 deleted file mode 100644 index f8725e1..0000000 --- a/templates/etc/ansible/compliance_facts.j2 +++ /dev/null @@ -1,40 +0,0 @@ -# CIS Hardening Carried out -# Added as part of ansible-lockdown CIS baseline -# provided by Mindpoint Group - A Tyto Athene Company - -[lockdown_details] -# Benchmark release -Benchmark_release = CIS-{{ benchmark_version }} -Benchmark_run_date = {{ '%Y-%m-%d - %H:%M:%S' | ansible.builtin.strftime }} -# If options set (doesn't mean it ran all controls) -level_1_hardening_enabled = {{ rhel9cis_level_1 }} -level_2_hardening_enabled = {{ rhel9cis_level_2 }} - -{% if ansible_run_tags | length > 0 %} -# If tags used to stipulate run level -{% if 'level1-server' in ansible_run_tags %} -Level_1_Server_tag_run = true -{% endif %} -{% if 'level2-server' in ansible_run_tags %} -Level_2_Server_tag_run = true -{% endif %} -{% if 'level1-workstation' in ansible_run_tags %} -Level_1_workstation_tag_run = true -{% endif %} -{% if 'level2-workstation' in ansible_run_tags %} -Level_2_workstation_tag_run = true -{% endif %} -{% endif %} - -[lockdown_audit_details] -{% if run_audit %} -# Audit run -audit_run_date = {{ '%Y-%m-%d - %H:%M:%S' | ansible.builtin.strftime }} -audit_file_local_location = {{ audit_log_dir }} -{% if not audit_only %} -audit_summary = {{ post_audit_results }} -{% endif %} -{% if fetch_audit_output %} -audit_files_centralized_location = {{ audit_output_destination }} -{% endif %} -{% endif %} diff --git a/templates/etc/chrony.conf.j2 b/templates/etc/chrony.conf.j2 index cc5cd84..54c1b6c 100644 --- a/templates/etc/chrony.conf.j2 +++ b/templates/etc/chrony.conf.j2 @@ -1,42 +1,95 @@ -{{ ansible_managed | comment }} +## This file is managed by Ansible, YOUR CHANGED WILL BE LOST! + +# This the default chrony.conf file for the Debian chrony package. After +# editing this file use the command 'invoke-rc.d chrony restart' to make +# your changes take effect. John Hasler 1998-2008 + +# See www.pool.ntp.org for an explanation of these servers. Please +# consider joining the project if possible. If you can't or don't want to +# use these servers I suggest that you try your ISP's nameservers. We mark +# the servers 'offline' so that chronyd won't try to connect when the link +# is down. Scripts in /etc/ppp/ip-up.d and /etc/ppp/ip-down.d use chronyc +# commands to switch it on when a dialup link comes up and off when it goes +# down. Code in /etc/init.d/chrony attempts to determine whether or not +# the link is up at boot time and set the online status accordingly. If +# you have an always-on connection such as cable omit the 'offline' +# directive and chronyd will default to online. +# +# Note that if Chrony tries to go "online" and dns lookup of the servers +# fails they will be discarded. Thus under some circumstances it is +# better to use IP numbers than host names. -# Use public servers from the pool.ntp.org project. -# Please consider joining the pool (http://www.pool.ntp.org/join.html). {% for server in rhel9cis_time_synchronization_servers -%} server {{ server }} {{ rhel9cis_chrony_server_options }} {% endfor %} -# Record the rate at which the system clock gains/losses time. -driftfile /var/lib/chrony/drift +# Look here for the admin password needed for chronyc. The initial +# password is generated by a random process at install time. You may +# change it if you wish. -# Allow the system clock to be stepped in the first three updates -# if its offset is larger than 1 second. -makestep 1.0 3 +keyfile /etc/chrony/chrony.keys -# Enable kernel synchronization of the real-time clock (RTC). -rtcsync +# Set runtime command key. Note that if you change the key (not the +# password) to anything other than 1 you will need to edit +# /etc/ppp/ip-up.d/chrony, /etc/ppp/ip-down.d/chrony, /etc/init.d/chrony +# and /etc/cron.weekly/chrony as these scripts use it to get the password. -# Enable hardware timestamping on all interfaces that support it. -#hwtimestamp * +commandkey 1 -# Increase the minimum number of selectable sources required to adjust -# the system clock. -#minsources 2 +# I moved the driftfile to /var/lib/chrony to comply with the Debian +# filesystem standard. -# Allow NTP client access from local network. -#allow 192.168.0.0/16 +driftfile /var/lib/chrony/chrony.drift -# Serve time even if not synchronized to a time source. -#local stratum 10 +# Comment this line out to turn off logging. -# Specify file containing keys for NTP authentication. -keyfile /etc/chrony.keys - -# Get TAI-UTC offset and leap seconds from the system tz database. -leapsectz right/UTC - -# Specify directory for log files. +log tracking measurements statistics logdir /var/log/chrony -# Select which information is logged. -#log measurements statistics tracking +# Stop bad estimates upsetting machine clock. + +maxupdateskew 100.0 + +# Dump measurements when daemon exits. + +dumponexit + +# Specify directory for dumping measurements. + +dumpdir /var/lib/chrony + +# Let computer be a server when it is unsynchronised. + +local stratum 10 + +# Allow computers on the unrouted nets to use the server. + +#allow 10/8 +#allow 192.168/16 +#allow 172.16/12 + +# This directive forces `chronyd' to send a message to syslog if it +# makes a system clock adjustment larger than a threshold value in seconds. + +logchange 0.5 + +# This directive defines an email address to which mail should be sent +# if chronyd applies a correction exceeding a particular threshold to the +# system clock. + +# mailonchange root@localhost 0.5 + +# This directive tells chrony to regulate the real-time clock and tells it +# Where to store related data. It may not work on some newer motherboards +# that use the HPET real-time clock. It requires enhanced real-time +# support in the kernel. I've commented it out because with certain +# combinations of motherboard and kernel it is reported to cause lockups. + +# rtcfile /var/lib/chrony/chrony.rtc + +# If the last line of this file reads 'rtconutc' chrony will assume that +# the CMOS clock is on UTC (GMT). If it reads '# rtconutc' or is absent +# chrony will assume local time. The line (if any) was written by the +# chrony postinst based on what it found in /etc/default/rcS. You may +# change it if necessary. +rtconutc diff --git a/templates/etc/cron.d/aide.cron.j2 b/templates/etc/cron.d/aide.cron.j2 index 4c1af92..21270eb 100644 --- a/templates/etc/cron.d/aide.cron.j2 +++ b/templates/etc/cron.d/aide.cron.j2 @@ -1,7 +1,7 @@ -# Run AIDE integrity check +# Run AIDE integrity check ## Ansible controlled file -# Added as part of ansible-lockdown CIS baseline -# provided by Mindpoint Group - A Tyto Athene Company +# Added as part of ansible-lockdown CIS baseline +# provided by MindPointGroup LLC ### YOUR CHANGES WILL BE LOST! # CIS 1.3.2 diff --git a/templates/etc/crypto-policies/policies/modules/NO-SHA1.pmod.j2 b/templates/etc/crypto-policies/policies/modules/NO-SHA1.pmod.j2 deleted file mode 100644 index fd6eaff..0000000 --- a/templates/etc/crypto-policies/policies/modules/NO-SHA1.pmod.j2 +++ /dev/null @@ -1,6 +0,0 @@ -# This is a subpolicy dropping the SHA1 hash and signature support -# Carried out as part of CIS Benchmark rule 1.6.3 - -hash = -SHA1 -sign = -*-SHA1 -sha1_in_certs = 0 diff --git a/templates/etc/crypto-policies/policies/modules/NO-SSHCBC.pmod.j2 b/templates/etc/crypto-policies/policies/modules/NO-SSHCBC.pmod.j2 deleted file mode 100644 index 9092036..0000000 --- a/templates/etc/crypto-policies/policies/modules/NO-SSHCBC.pmod.j2 +++ /dev/null @@ -1,5 +0,0 @@ -# This is a subpolicy to disable all CBC mode ciphers -# for the SSH protocol (libssh and OpenSSH) -# Carried out as part of CIS Benchmark rule 1.6.5 - -cipher@SSH = -*-CBC diff --git a/templates/etc/crypto-policies/policies/modules/NO-SSHETM.pmod.j2 b/templates/etc/crypto-policies/policies/modules/NO-SSHETM.pmod.j2 deleted file mode 100644 index cebc2ad..0000000 --- a/templates/etc/crypto-policies/policies/modules/NO-SSHETM.pmod.j2 +++ /dev/null @@ -1,5 +0,0 @@ -# This is a subpolicy to disable Encrypt then MAC -# for the SSH protocol (libssh and OpenSSH) -# Carried out as part of CIS Benchmark rule 1.6.7 - -etm@SSH = DISABLE_ETM diff --git a/templates/etc/crypto-policies/policies/modules/NO-SSHWEAKCIPHERS.pmod.j2 b/templates/etc/crypto-policies/policies/modules/NO-SSHWEAKCIPHERS.pmod.j2 deleted file mode 100644 index 393cf88..0000000 --- a/templates/etc/crypto-policies/policies/modules/NO-SSHWEAKCIPHERS.pmod.j2 +++ /dev/null @@ -1,4 +0,0 @@ -# This is a subpolicy to disable weak ciphers -# for the SSH protocol (libssh and OpenSSH) -# Carried out as part of CIS Benchmark rules combined 1.6.6 and 5.1.4 -cipher@SSH ={% if rhel9cis_rule_1_6_6 %} -CHACHA20-POLY1305{% endif %}{% if rhel9cis_rule_5_1_4 %} -3DES-CBC -AES-128-CBC -AES-192-CBC -AES-256-CBC{% endif %} diff --git a/templates/etc/crypto-policies/policies/modules/NO-SSHWEAKMACS.pmod.j2 b/templates/etc/crypto-policies/policies/modules/NO-SSHWEAKMACS.pmod.j2 deleted file mode 100644 index f040399..0000000 --- a/templates/etc/crypto-policies/policies/modules/NO-SSHWEAKMACS.pmod.j2 +++ /dev/null @@ -1,4 +0,0 @@ -# This is a subpolicy to disable weak macs -# Carried out as part of CIS Benchmark control 5.1.6 - -mac@SSH = -HMAC-MD5* -UMAC-64* -UMAC-128* diff --git a/templates/etc/crypto-policies/policies/modules/NO-WEAKMAC.pmod.j2 b/templates/etc/crypto-policies/policies/modules/NO-WEAKMAC.pmod.j2 deleted file mode 100644 index 0020e6d..0000000 --- a/templates/etc/crypto-policies/policies/modules/NO-WEAKMAC.pmod.j2 +++ /dev/null @@ -1,4 +0,0 @@ -# This is a subpolicy to disable weak macs -# Carried out as part of CIS Benchmark rule 1.6.4 - -mac = -*-64 diff --git a/templates/etc/dconf/db/00-automount_lock.j2 b/templates/etc/dconf/db/00-automount_lock.j2 index 0e55b5a..d92c56b 100644 --- a/templates/etc/dconf/db/00-automount_lock.j2 +++ b/templates/etc/dconf/db/00-automount_lock.j2 @@ -1,6 +1,6 @@ ## Ansible controlled file -# Added as part of ansible-lockdown CIS baseline -# provided by Mindpoint Group - A Tyto Athene Company +# Added as part of ansible-lockdown CIS baseline +# provided by MindPointGroup LLC # Lock desktop media-handling automount setting /org/gnome/desktop/media-handling/automount diff --git a/templates/etc/dconf/db/00-autorun_lock.j2 b/templates/etc/dconf/db/00-autorun_lock.j2 index cf9ed5d..503069c 100644 --- a/templates/etc/dconf/db/00-autorun_lock.j2 +++ b/templates/etc/dconf/db/00-autorun_lock.j2 @@ -1,6 +1,6 @@ ## Ansible controlled file -# Added as part of ansible-lockdown CIS baseline -# provided by Mindpoint Group - A Tyto Athene Company +# Added as part of ansible-lockdown CIS baseline +# provided by MindPointGroup LLC -# Lock desktop media-handling settings +# Lock desktop media-handling settings /org/gnome/desktop/media-handling/autorun-never diff --git a/templates/etc/dconf/db/00-media-automount.j2 b/templates/etc/dconf/db/00-media-automount.j2 index 640538c..32192c3 100644 --- a/templates/etc/dconf/db/00-media-automount.j2 +++ b/templates/etc/dconf/db/00-media-automount.j2 @@ -1,6 +1,6 @@ ## Ansible controlled file -# Added as part of ansible-lockdown CIS baseline -# provided by Mindpoint Group - A Tyto Athene Company +# Added as part of ansible-lockdown CIS baseline +# provided by MindPointGroup LLC [org/gnome/desktop/media-handling] automount=false diff --git a/templates/etc/dconf/db/00-media-autorun.j2 b/templates/etc/dconf/db/00-media-autorun.j2 index 382469c..16ded9d 100644 --- a/templates/etc/dconf/db/00-media-autorun.j2 +++ b/templates/etc/dconf/db/00-media-autorun.j2 @@ -1,6 +1,6 @@ ## Ansible controlled file -# Added as part of ansible-lockdown CIS baseline -# provided by Mindpoint Group - A Tyto Athene Company +# Added as part of ansible-lockdown CIS baseline +# provided by MindPointGroup LLC [org/gnome/desktop/media-handling] autorun-never=true diff --git a/templates/etc/dconf/db/00-screensaver.j2 b/templates/etc/dconf/db/00-screensaver.j2 index a747336..0b9f686 100644 --- a/templates/etc/dconf/db/00-screensaver.j2 +++ b/templates/etc/dconf/db/00-screensaver.j2 @@ -1,6 +1,7 @@ ## Ansible controlled file -# Added as part of ansible-lockdown CIS baseline -# provided by Mindpoint Group - A Tyto Athene Company +# Added as part of ansible-lockdown CIS baseline +# provided by MindPointGroup LLC + # Specify the dconf path [org/gnome/desktop/session] diff --git a/templates/etc/dconf/db/00-screensaver_lock.j2 b/templates/etc/dconf/db/00-screensaver_lock.j2 index 5988316..fae6e82 100644 --- a/templates/etc/dconf/db/00-screensaver_lock.j2 +++ b/templates/etc/dconf/db/00-screensaver_lock.j2 @@ -1,6 +1,6 @@ ## Ansible controlled file -# Added as part of ansible-lockdown CIS baseline -# provided by Mindpoint Group - A Tyto Athene Company +# Added as part of ansible-lockdown CIS baseline +# provided by MindPointGroup LLC # Lock desktop screensaver idle-delay setting /org/gnome/desktop/session/idle-delay diff --git a/templates/etc/dconf/db/gdm.d/01-banner-message.j2 b/templates/etc/dconf/db/gdm.d/01-banner-message.j2 index ec42bfc..73b4505 100644 --- a/templates/etc/dconf/db/gdm.d/01-banner-message.j2 +++ b/templates/etc/dconf/db/gdm.d/01-banner-message.j2 @@ -1,7 +1,7 @@ ## Ansible controlled file -# Added as part of ansible-lockdown CIS baseline -# provided by Mindpoint Group - A Tyto Athene Company +# Added as part of ansible-lockdown CIS baseline +# provided by MindPointGroup LLC [org/gnome/login-screen] banner-message-enable=true -banner-message-text="{{ rhel9cis_warning_banner | trim | replace("\n", "\\n") }}" +banner-message-text="{{ rhel9cis_warning_banner }}" diff --git a/templates/etc/logrotate.d/rsyslog_log.j2 b/templates/etc/logrotate.d/rsyslog_log.j2 deleted file mode 100644 index 8acb53e..0000000 --- a/templates/etc/logrotate.d/rsyslog_log.j2 +++ /dev/null @@ -1,26 +0,0 @@ -/var/log/rsyslog/*.log { - {{ rhel9cis_rsyslog_logrotate_rotated_when }} - rotate {{ rhel9cis_rsyslog_logrotate_rotatation_keep }} -{% if rhel9cis_rsyslog_logrotate_compress %} - compress -{% else %} - nocompress -{% endif %} -{% if rhel9cis_rsyslog_logrotate_missingok %} - missingok -{% else %} - nomissingok -{% endif %} -{% if rhel9cis_rsyslog_logrotate_notifempty %} - notifempty -{% else %} - ifempty -{% endif %} -{% if rhel9cis_rsyslog_logrotate_create %} - create{% if rhel9cis_rsyslog_logrotate_create_opts is defined %} {{ rhel9cis_rsyslog_logrotate_create_opts }}{% endif %} -{% endif %} - - postrotate - /usr/bin/systemctl reload rsyslog.service >/dev/null || true - endscript -} diff --git a/templates/etc/security/pwquality.conf.d/50-pwcomplexity.conf.j2 b/templates/etc/security/pwquality.conf.d/50-pwcomplexity.conf.j2 deleted file mode 100644 index c223c84..0000000 --- a/templates/etc/security/pwquality.conf.d/50-pwcomplexity.conf.j2 +++ /dev/null @@ -1,11 +0,0 @@ -# CIS Configurations -# 5.3.3.2.3 Ensure password complexity is configured -{% if rhel9cis_passwd_complex_option == 'minclass' %} # pragma: allowlist secret -minclass = {{ rhel9cis_passwd_minclass }} -{% endif %} -{% if rhel9cis_passwd_complex_option == 'credits' %} # pragma: allowlist secret -dcredit = {{rhel9cis_passwd_dcredit }} -ucredit = {{ rhel9cis_passwd_ucredit }} -ocredit = {{ rhel9cis_passwd_ocredit }} -lcredit = {{ rhel9cis_passwd_lcredit }} -{% endif %} diff --git a/templates/etc/security/pwquality.conf.d/50-pwdictcheck.conf.j2 b/templates/etc/security/pwquality.conf.d/50-pwdictcheck.conf.j2 deleted file mode 100644 index 09b6ee3..0000000 --- a/templates/etc/security/pwquality.conf.d/50-pwdictcheck.conf.j2 +++ /dev/null @@ -1,3 +0,0 @@ -# CIS Configurations -# 5.3.3.2.6 Ensure password dictionary check is enabled -dictcheck = {{ rhel9cis_passwd_dictcheck_value }} diff --git a/templates/etc/security/pwquality.conf.d/50-pwdifok.conf.j2 b/templates/etc/security/pwquality.conf.d/50-pwdifok.conf.j2 deleted file mode 100644 index 2e8ae2d..0000000 --- a/templates/etc/security/pwquality.conf.d/50-pwdifok.conf.j2 +++ /dev/null @@ -1,3 +0,0 @@ -# CIS Configurations -# 5.3.3.2.1 Ensure password number of changed characters is configured -difok = {{ rhel9cis_passwd_difok_value }} diff --git a/templates/etc/security/pwquality.conf.d/50-pwlength.conf.j2 b/templates/etc/security/pwquality.conf.d/50-pwlength.conf.j2 deleted file mode 100644 index 9e874ee..0000000 --- a/templates/etc/security/pwquality.conf.d/50-pwlength.conf.j2 +++ /dev/null @@ -1,3 +0,0 @@ -# CIS Configurations -# 5.3.3.2.2 Ensure minimum password length is configured -minlen = {{ rhel9cis_passwd_minlen_value }} diff --git a/templates/etc/security/pwquality.conf.d/50-pwmaxsequence.conf.j2 b/templates/etc/security/pwquality.conf.d/50-pwmaxsequence.conf.j2 deleted file mode 100644 index a561fec..0000000 --- a/templates/etc/security/pwquality.conf.d/50-pwmaxsequence.conf.j2 +++ /dev/null @@ -1,3 +0,0 @@ -# CIS Configurations -# 5.3.3.2.5 Ensure password maximum sequential characters is configured -maxsequence = {{ rhel9cis_passwd_maxsequence_value }} diff --git a/templates/etc/security/pwquality.conf.d/50-pwquality_enforce.conf.j2 b/templates/etc/security/pwquality.conf.d/50-pwquality_enforce.conf.j2 deleted file mode 100644 index 6fea8db..0000000 --- a/templates/etc/security/pwquality.conf.d/50-pwquality_enforce.conf.j2 +++ /dev/null @@ -1,3 +0,0 @@ -# CIS Configurations -# 5.3.3.2.7 Ensure password quality checking is enforced -enforcing = {{ rhel9cis_passwd_quality_enforce_value }} diff --git a/templates/etc/security/pwquality.conf.d/50-pwrepeat.conf.j2 b/templates/etc/security/pwquality.conf.d/50-pwrepeat.conf.j2 deleted file mode 100644 index 28b8dde..0000000 --- a/templates/etc/security/pwquality.conf.d/50-pwrepeat.conf.j2 +++ /dev/null @@ -1,3 +0,0 @@ -# CIS Configurations -# 5.3.3.2.4 Ensure password same consecutive characters is configured -maxrepeat = {{ rhel9cis_passwd_maxrepeat_value }} diff --git a/templates/etc/security/pwquality.conf.d/50-pwroot.conf.j2 b/templates/etc/security/pwquality.conf.d/50-pwroot.conf.j2 deleted file mode 100644 index 9effdae..0000000 --- a/templates/etc/security/pwquality.conf.d/50-pwroot.conf.j2 +++ /dev/null @@ -1,3 +0,0 @@ -# CIS Configurations -# 5.3.3.2.8 Ensure password quality is enforced for the root user -{{ rhel9cis_passwd_quality_enforce_root_value }} diff --git a/templates/etc/sysctl.d/60-disable_ipv6.conf.j2 b/templates/etc/sysctl.d/60-disable_ipv6.conf.j2 index b4b5318..732cbcc 100644 --- a/templates/etc/sysctl.d/60-disable_ipv6.conf.j2 +++ b/templates/etc/sysctl.d/60-disable_ipv6.conf.j2 @@ -1,10 +1,7 @@ ## This file is managed by Ansible, YOUR CHANGES WILL BE LOST! # IPv6 disable -{% if rhel9cis_rule_3_1_1 and not rhel9cis_ipv6_required %} -net.ipv6.conf.all.disable_ipv6 = 1 +{% if rhel9cis_rule_3_1_1 and rhel9cis_ipv6_required %} +net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 -{% for interface in ansible_interfaces %} -net.ipv6.conf.{{ interface }}.disable_ipv6 = 1 -{% endfor %} {% endif %} diff --git a/templates/etc/sysctl.d/60-kernel_sysctl.conf.j2 b/templates/etc/sysctl.d/60-kernel_sysctl.conf.j2 index 11a93f2..8bd0157 100644 --- a/templates/etc/sysctl.d/60-kernel_sysctl.conf.j2 +++ b/templates/etc/sysctl.d/60-kernel_sysctl.conf.j2 @@ -1,12 +1,8 @@ ## This file is managed by Ansible, YOUR CHANGES WILL BE LOST! -{% if rhel9cis_rule_1_5_1 %} -# Adress space randomise -# CIS 1.5.1 + +{% if rhel9cis_rule_1_5_3 %} +# Kernel sysctl +# CIS 1.5.3 kernel.randomize_va_space = 2 -{% endif %} -{% if rhel9cis_rule_1_5_2 %} -# Ptrace scope -# CIS 1.5.2 -kernel.yama.ptrace_scope = 1 -{% endif %} +{% endif %} \ No newline at end of file diff --git a/templates/etc/sysctl.d/60-netipv4_sysctl.conf.j2 b/templates/etc/sysctl.d/60-netipv4_sysctl.conf.j2 index 336071c..8bafbf9 100644 --- a/templates/etc/sysctl.d/60-netipv4_sysctl.conf.j2 +++ b/templates/etc/sysctl.d/60-netipv4_sysctl.conf.j2 @@ -1,33 +1,43 @@ ## This file is managed by Ansible, YOUR CHANGES WILL BE LOST! # IPv4 Network sysctl -{% if rhel9cis_rule_3_3_1 %} -# CIS 3.3.1 +{% if rhel9cis_rule_3_2_1 %} +# CIS 3.2.1 net.ipv4.ip_forward = 0 {% endif %} -{% if rhel9cis_rule_3_3_2 %} -# CIS 3.3.2 +{% if rhel9cis_rule_3_2_2 %} +# CIS 3.2.2 net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.default.send_redirects = 0 {% endif %} -{% if rhel9cis_rule_3_3_3 %} -# CIS 3.3.3 -net.ipv4.icmp_ignore_bogus_error_responses = 1 +{% if rhel9cis_rule_3_3_1 %} +# CIS 3.3.1 +net.ipv4.conf.all.accept_source_route = 0 +net.ipv4.conf.default.accept_source_route = 0 {% endif %} -{% if rhel9cis_rule_3_3_4 %} -# CIS 3.3.4 -net.ipv4.icmp_echo_ignore_broadcasts = 1 -{% endif %} -{% if rhel9cis_rule_3_3_5 %} -# CIS 3.3.5 +{% if rhel9cis_rule_3_3_2 %} +# CIS 3.3.2 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 {% endif %} -{% if rhel9cis_rule_3_3_6 %} -# CIS 3.3.6 +{% if rhel9cis_rule_3_3_3 %} +# CIS 3.3.3 net.ipv4.conf.all.secure_redirects = 0 net.ipv4.conf.default.secure_redirects = 0 {% endif %} +{% if rhel9cis_rule_3_3_4 %} +# CIS 3.3.4 +net.ipv4.conf.all.log_martians = 1 +net.ipv4.conf.default.log_martians = 1 +{% endif %} +{% if rhel9cis_rule_3_3_5 %} +# CIS 3.3.5 +net.ipv4.icmp_echo_ignore_broadcasts = 1 +{% endif %} +{% if rhel9cis_rule_3_3_6 %} +# CIS 3.3.6 +net.ipv4.icmp_ignore_bogus_error_responses = 1 +{% endif %} {% if rhel9cis_rule_3_3_7 %} # CIS 3.3.7 net.ipv4.conf.all.rp_filter = 1 @@ -35,15 +45,5 @@ net.ipv4.conf.default.rp_filter = 1 {% endif %} {% if rhel9cis_rule_3_3_8 %} # CIS 3.3.8 -net.ipv4.conf.all.accept_source_route = 0 -net.ipv4.conf.default.accept_source_route = 0 -{% endif %} -{% if rhel9cis_rule_3_3_9 %} -# CIS 3.3.9 -net.ipv4.conf.all.log_martians = 1 -net.ipv4.conf.default.log_martians = 1 -{% endif %} -{% if rhel9cis_rule_3_3_10 %} -# CIS 3.3.10 net.ipv4.tcp_syncookies = 1 {% endif %} diff --git a/templates/etc/sysctl.d/60-netipv6_sysctl.conf.j2 b/templates/etc/sysctl.d/60-netipv6_sysctl.conf.j2 index 07e045d..e85fae9 100644 --- a/templates/etc/sysctl.d/60-netipv6_sysctl.conf.j2 +++ b/templates/etc/sysctl.d/60-netipv6_sysctl.conf.j2 @@ -2,23 +2,20 @@ # IPv6 Network sysctl {% if rhel9cis_ipv6_required %} -{% if rhel9cis_rule_3_3_1 %} -# CIS 3.3.1 +{% if rhel9cis_rule_3_2_1 %} net.ipv6.conf.all.forwarding = 0 {% endif %} -{% if rhel9cis_rule_3_3_5 %} -# CIS 3.3.5 -net.ipv6.conf.all.accept_redirects = 0 -net.ipv6.conf.default.accept_redirects = 0 -{% endif %} -{% if rhel9cis_rule_3_3_8 %} -# CIS 3.3.8 +{% if rhel9cis_rule_3_3_1 %} net.ipv6.conf.all.accept_source_route = 0 net.ipv6.conf.default.accept_source_route = 0 {% endif %} -{% if rhel9cis_rule_3_3_11 %} -# CIS 3.3.11 +{% if rhel9cis_rule_3_3_2 %} +net.ipv6.conf.all.accept_redirects = 0 +net.ipv6.conf.default.accept_redirects = 0 +{% endif %} +{% if rhel9cis_rule_3_3_9 %} +# CIS 3.3.9 net.ipv6.conf.all.accept_ra = 0 net.ipv6.conf.default.accept_ra = 0 {% endif %} -{% endif %} +{% endif %} \ No newline at end of file diff --git a/templates/etc/systemd/journald.conf.d/forwardtosyslog.conf.j2 b/templates/etc/systemd/journald.conf.d/forwardtosyslog.conf.j2 deleted file mode 100644 index 3b00ce1..0000000 --- a/templates/etc/systemd/journald.conf.d/forwardtosyslog.conf.j2 +++ /dev/null @@ -1,4 +0,0 @@ -# File created for CIS benchmark -# CIS rule 6_2_2_2 -[Journal] -ForwardToSyslog=no diff --git a/templates/etc/systemd/journald.conf.d/rotation.conf.j2 b/templates/etc/systemd/journald.conf.d/rotation.conf.j2 deleted file mode 100644 index 07eedba..0000000 --- a/templates/etc/systemd/journald.conf.d/rotation.conf.j2 +++ /dev/null @@ -1,8 +0,0 @@ -# File created for CIS benchmark -# CIS rule 6_2_1_3 -[Journal] -SystemMaxUse={{ rhel9cis_journald_systemmaxuse }} -SystemKeepFree={{ rhel9cis_journald_systemkeepfree }} -RuntimeMaxUse={{ rhel9cis_journald_runtimemaxuse }} -RuntimeKeepFree={{ rhel9cis_journald_runtimekeepfree }} -MaxFileSec={{ rhel9cis_journald_maxfilesec }} diff --git a/templates/etc/systemd/journald.conf.d/storage.conf.j2 b/templates/etc/systemd/journald.conf.d/storage.conf.j2 deleted file mode 100644 index 214f9db..0000000 --- a/templates/etc/systemd/journald.conf.d/storage.conf.j2 +++ /dev/null @@ -1,11 +0,0 @@ -# File created for CIS benchmark -[Journal] -{% if rhel9cis_rule_6_2_2_3 %} -# Set compress CIS rule 6_2_2_3 -Compress=yes -{% endif %} - -{% if rhel9cis_rule_6_2_2_4 %} -# Set persistent storage CIS rule 6_2_2_4 -Storage=persistent -{% endif %} diff --git a/templates/etc/systemd/system/tmp.mount.j2 b/templates/etc/systemd/system/tmp.mount.j2 index 7f64547..3f689ee 100644 --- a/templates/etc/systemd/system/tmp.mount.j2 +++ b/templates/etc/systemd/system/tmp.mount.j2 @@ -23,7 +23,7 @@ After=swap.target What=tmpfs Where=/tmp Type=tmpfs -Options=mode=1777,strictatime,{% if rhel9cis_rule_1_1_2_1_2 %}nodev,{% endif %}{% if rhel9cis_rule_1_1_2_1_3 %}nosuid,{% endif %}{% if rhel9cis_rule_1_1_2_1_4 %}noexec{% endif %} +Options=mode=1777,strictatime,{% if rhel9cis_rule_1_1_2_2 %}nodev,{% endif %}{% if rhel9cis_rule_1_1_2_4 %}nosuid,{% endif %}{% if rhel9cis_rule_1_1_2_3 %}noexec{% endif %} # Make 'systemctl enable tmp.mount' work: [Install] diff --git a/vars/AlmaLinux.yml b/vars/AlmaLinux.yml index b0eb3d9..c460fb0 100644 --- a/vars/AlmaLinux.yml +++ b/vars/AlmaLinux.yml @@ -3,5 +3,3 @@ os_gpg_key_pubkey_name: gpg-pubkey-b86b3716-61e69f29 os_gpg_key_pubkey_content: "AlmaLinux OS 9 b86b3716" -# disable repo_gpgcheck due to OS default repos -rhel9cis_rule_enable_repogpg: false diff --git a/vars/CentOS.yml b/vars/CentOS.yml deleted file mode 100644 index 08ca326..0000000 --- a/vars/CentOS.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- - -os_gpg_key_pubkey_name: centos-gpg-keys -os_gpg_key_pubkey_content: "builder@centos.org 9.0" diff --git a/vars/OracleLinux.yml b/vars/OracleLinux.yml index 64927cc..d916178 100644 --- a/vars/OracleLinux.yml +++ b/vars/OracleLinux.yml @@ -2,5 +2,3 @@ # OS Specific Settings os_gpg_key_pubkey_name: gpg-pubkey-8d8b756f-629e59ec os_gpg_key_pubkey_content: "Oracle Linux (release key 1) " -# disable repo_gpgcheck due to OS default repos -rhel9cis_rule_enable_repogpg: false diff --git a/vars/RedHat.yml b/vars/RedHat.yml index c5833a4..d33b0bc 100644 --- a/vars/RedHat.yml +++ b/vars/RedHat.yml @@ -3,6 +3,3 @@ os_gpg_key_pubkey_name: gpg-pubkey-fd431d51-4ae0493b os_gpg_key_pubkey_content: "Red Hat, Inc. (release key 2) fd431d51" - -# disable repo_gpgcheck due to OS default repos -rhel9cis_rule_enable_repogpg: false diff --git a/vars/audit.yml b/vars/audit.yml deleted file mode 100644 index 1dc1cf1..0000000 --- a/vars/audit.yml +++ /dev/null @@ -1,41 +0,0 @@ ---- - -#### Audit Configuration Settings #### - -# Timeout for those cmds that take longer to run where timeout set -audit_cmd_timeout: 120000 - -# if get_audit_binary_method == download change accordingly -audit_bin_url: "https://github.com/goss-org/goss/releases/download/{{ audit_bin_version.release }}/goss-linux-" - -### Goss Audit Benchmark file ### -## managed by the control audit_content -# git -audit_file_git: "https://github.com/ansible-lockdown/{{ benchmark }}-Audit.git" -audit_git_version: "benchmark_{{ benchmark_version }}" - -## Goss configuration information -# Where the goss audit configuration will be stored - NOTE benchmark-audit is expected -audit_conf_dir: "{{ audit_conf_dest | default('/opt') }}/{{ benchmark }}-Audit" - -# If changed these can affect other products -pre_audit_outfile: "{{ audit_log_dir }}/{{ ansible_facts.hostname }}-{{ benchmark }}-{{ benchmark_version }}_pre_scan_{{ ansible_facts.date_time.epoch }}.{{ audit_format }}" -post_audit_outfile: "{{ audit_log_dir }}/{{ ansible_facts.hostname }}-{{ benchmark }}-{{ benchmark_version }}_post_scan_{{ ansible_facts.date_time.epoch }}.{{ audit_format }}" - -## The following should not need changing - -### Audit binary settings ### -audit_bin_version: - release: v0.4.8 - AMD64_checksum: 'sha256:85d00b7bba5f175bec95de7dfe1f71f8f25204914aad4c6f03c8457868eb6e2f' - ARM64_checksum: 'sha256:bca8c898bfd35b94c51455ece6193c95e2cd7b2b183ac2047b2d76291e73e47d' -audit_bin_path: /usr/local/bin/ -audit_bin: "{{ audit_bin_path }}goss" -audit_format: json - -audit_vars_path: "{{ audit_conf_dir }}/vars/{{ ansible_facts.hostname }}.yml" -audit_results: | - The{% if not audit_only %} pre remediation{% endif %} audit results are: {{ pre_audit_results }} - {% if not audit_only %}The post remediation audit results are: {{ post_audit_results }}{% endif %} - - Full breakdown can be found in {{ audit_log_dir }} diff --git a/vars/main.yml b/vars/main.yml index 9337d58..2a93184 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -3,74 +3,12 @@ min_ansible_version: 2.10.1 rhel9cis_allowed_crypto_policies: - - 'DEFAULT' - - 'FUTURE' - - 'FIPS' - -# Following is left blank for ability to build string -rhel9cis_crypto_policy_module: '' - -# Do not adjust these are recognized as part of the CIS benchmark and used during testing -rhel9cis_allowed_crypto_policies_modules: - # Recognized by CIS as possible extra options - - 'OSPP' - - 'AD-SUPPORT' - - 'AD-SUPPORT-LEGACY' - # The following are already included in 1.6.x controls - - 'NO-SHA1' - - 'NO-SSHCBC' - - 'NO-SSHETM' - - 'NO-SSHWEAKCIPHER' - - 'NO-SSHWEAKMAC' - - 'NO-WEAKMAC' + - 'DEFAULT' + - 'FUTURE' + - 'FIPS' # Used to control warning summary warn_control_list: "" warn_count: 0 -# list of dicts of interactive users, filled in during prelim.yml -prelim_interactive_users: [] - -# Default empty values for 1.4.2 -efi_mount_opts_addition: '' - -gpg_key_package: "{{ ansible_facts.distribution | lower }}-gpg-keys" - -## Controls 6.3.3.x - Audit template -# This variable is set to true by tasks 6.3.3.1 to 6.3.3.20. As a result, the -# audit settings are overwritten with the role's template. In order to exclude -# specific rules, you must set the variable of form `ubtu24cis_rule_6_3_3_x` above -# to `false`. -update_audit_template: false - -# Defaults -## Usage on containerized images -# The role discovers dynamically (in tasks/main.yml) whether it -# is executed on a container image and sets the variable -# system_is_container the true. Otherwise, the default value -# 'false' is left unchanged. -system_is_container: false -# The filename of the existing yml file in role's 'vars/' sub-directory -# to be used for managing the role-behavior when a container was detected: -# (de)activating rules or for other tasks(e.g. disabling Selinux or a specific -# firewall-type). -container_vars_file: is_container.yml -# rhel9cis is left off the front of this var for consistency in testing pipeline -# system_is_ec2 toggle will disable tasks that fail on Amazon EC2 instances. Set true to skip and false to run tasks -system_is_ec2: false - -# Aide Packages - -aide_packages: - - aide -# Aide initiate command for new DB creation -aide_initiate_command: /usr/sbin/aide --init - -# Audit vars -audit_bins: - - /sbin/auditctl - - /sbin/aureport - - /sbin/ausearch - - /sbin/autrace - - /sbin/auditd - - /sbin/augenrules +gpg_key_package: "{{ ansible_distribution | lower }}-gpg-keys"