├── .ansible-lint ├── .gitattributes ├── .github └── workflows │ ├── AMAZON2.tfvars │ ├── devel_pipeline_validation.yml │ ├── main.tf │ ├── main_pipeline_validation.yml │ ├── update_galaxy.yml │ └── variables.tf ├── .gitignore ├── .pre-commit-config.yaml ├── .yamllint ├── CONTRIBUTING.rst ├── LICENSE ├── README.md ├── ansible.cfg ├── collections └── requirements.yml ├── defaults └── main.yml ├── handlers └── main.yml ├── meta └── main.yml ├── site.yml ├── tasks ├── LE_audit_setup.yml ├── audit_only.yml ├── auditd.yml ├── check_prereqs.yml ├── fetch_audit_output.yml ├── main.yml ├── parse_etc_password.yml ├── post.yml ├── post_remediation_audit.yml ├── pre_remediation_audit.yml ├── prelim.yml ├── section_1 │ ├── cis_1.1.1.x.yml │ ├── cis_1.1.2.1.x.yml │ ├── cis_1.1.2.2.x.yml │ ├── cis_1.1.2.3.x.yml │ ├── cis_1.1.2.4.x.yml │ ├── cis_1.1.2.5.x.yml │ ├── cis_1.1.2.6.x.yml │ ├── cis_1.1.2.7.x.yml │ ├── cis_1.2.x.yml │ ├── cis_1.3.x.yml │ ├── cis_1.4.x.yml │ ├── cis_1.5.x.yml │ ├── cis_1.6.x.yml │ └── main.yml ├── section_2 │ ├── cis_2.1.x.yml │ ├── cis_2.2.x.yml │ ├── cis_2.3.x.yml │ └── main.yml ├── section_3 │ ├── cis_3.1.x.yml │ ├── cis_3.2.x.yml │ ├── cis_3.3.x.yml │ ├── cis_3.4.1.x.yml │ ├── cis_3.4.2.x.yml │ ├── cis_3.4.3.x.yml │ ├── cis_3.4.4.1.x.yml │ ├── cis_3.4.4.2.x.yml │ ├── cis_3.4.4.3.x.yml │ └── main.yml ├── section_4 │ ├── cis_4.1.x.x.yml │ ├── cis_4.2.x.yml │ ├── cis_4.3.x.yml │ ├── cis_4.4.1.x.yml │ ├── cis_4.4.2.1.x.yml │ ├── cis_4.4.2.2.x.yml │ ├── cis_4.4.2.3.x.yml │ ├── cis_4.4.2.4.x.yml │ ├── cis_4.5.1.x.yml │ ├── cis_4.5.2.x.yml │ ├── cis_4.5.3.x.yml │ └── main.yml ├── section_5 │ ├── cis_5.1.1.x.yml │ ├── cis_5.1.2.x.yml │ ├── cis_5.1.3.yml │ ├── cis_5.1.4.yml │ ├── cis_5.2.1.x.yml │ ├── cis_5.2.2.x.yml │ ├── cis_5.2.3.x.yml │ ├── cis_5.2.4.x.yml │ ├── cis_5.3.x.yml │ └── main.yml ├── section_6 │ ├── cis_6.1.x.yml │ ├── cis_6.2.x.yml │ └── main.yml └── warning_facts.yml ├── templates ├── ansible_vars_goss.yml.j2 ├── audit │ └── 99_auditd.rules.j2 ├── chrony.conf.j2 ├── etc │ ├── ansible │ │ └── compliance_facts.j2 │ ├── issue.j2 │ ├── issue.net.j2 │ ├── motd.j2 │ ├── systemd │ │ └── system │ │ │ └── tmp.mount.j2 │ └── tmp_mount.j2 └── ntp.conf.j2 └── vars ├── audit.yml └── main.yml /.ansible-lint: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | parseable: true 4 | quiet: true 5 | skip_list: 6 | - 'schema' 7 | - 'no-changed-when' 8 | - 'var-spacing' 9 | - 'experimental' 10 | - 'name[play]' 11 | - 'name[casing]' 12 | - 'name[template]' 13 | - 'key-order[task]' 14 | - '204' 15 | - '305' 16 | - '303' 17 | - '403' 18 | - '306' 19 | - '602' 20 | - '208' 21 | use_default_rules: true 22 | verbosity: 0 23 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # adding github settings to show correct language 2 | *.sh linguist-detectable=true 3 | *.yml linguist-detectable=true 4 | *.ps1 linguist-detectable=true 5 | *.j2 linguist-detectable=true 6 | *.md linguist-documentation 7 | -------------------------------------------------------------------------------- /.github/workflows/AMAZON2.tfvars: -------------------------------------------------------------------------------- 1 | # Amazon Linux 2 2 | ami_id = "ami-03e0b06f01d45a4eb" 3 | ami_os = "AmazonLinux2" 4 | ami_username = "ec2-user" 5 | ami_user_home = "/home/ec2-user" 6 | benchmark_os = "Amazon2" 7 | -------------------------------------------------------------------------------- /.github/workflows/devel_pipeline_validation.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: Devel pipeline 4 | 5 | on: # yamllint disable-line rule:truthy 6 | pull_request_target: 7 | types: [opened, reopened, synchronize] 8 | branches: 9 | - devel 10 | - benchmark* 11 | paths: 12 | - '**.yml' 13 | - '**.sh' 14 | - '**.j2' 15 | - '**.ps1' 16 | - '**.cfg' 17 | # Allow manual running of workflow 18 | workflow_dispatch: 19 | 20 | # Allow permissions for AWS auth 21 | permissions: 22 | id-token: write 23 | contents: read 24 | pull-requests: read 25 | 26 | # A workflow run is made up of one or more jobs 27 | # that can run sequentially or in parallel 28 | jobs: 29 | # This will create messages for first time contributers and direct them to the Discord server 30 | welcome: 31 | runs-on: ubuntu-latest 32 | 33 | steps: 34 | - uses: actions/first-interaction@main 35 | with: 36 | repo-token: ${{ secrets.GITHUB_TOKEN }} 37 | pr-message: |- 38 | Congrats on opening your first pull request and thank you for taking the time to help improve Ansible-Lockdown! 39 | Please join in the conversation happening on the [Discord Server](https://www.lockdownenterprise.com/discord) as well. 40 | 41 | # This workflow contains a single job that tests the playbook 42 | playbook-test: 43 | # The type of runner that the job will run on 44 | runs-on: self-hosted 45 | env: 46 | ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }} 47 | # Imported as a variable by terraform 48 | TF_VAR_repository: ${{ github.event.repository.name }} 49 | AWS_REGION: "us-east-1" 50 | ANSIBLE_VERSION: ${{ vars.ANSIBLE_RUNNER_VERSION }} 51 | defaults: 52 | run: 53 | shell: bash 54 | working-directory: .github/workflows/github_linux_IaC 55 | # working-directory: .github/workflows 56 | 57 | steps: 58 | 59 | - name: Git clone the lockdown repository to test 60 | uses: actions/checkout@v4 61 | with: 62 | ref: ${{ github.event.pull_request.head.sha }} 63 | 64 | - name: If a variable for IAC_BRANCH is set use that branch 65 | working-directory: .github/workflows 66 | run: | 67 | if [ ${{ vars.IAC_BRANCH }} != '' ]; then 68 | echo "IAC_BRANCH=${{ vars.IAC_BRANCH }}" >> $GITHUB_ENV 69 | echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}" 70 | else 71 | echo IAC_BRANCH=main >> $GITHUB_ENV 72 | fi 73 | 74 | # Pull in terraform code for linux servers 75 | - name: Clone GitHub IaC plan 76 | uses: actions/checkout@v4 77 | with: 78 | repository: ansible-lockdown/github_linux_IaC 79 | path: .github/workflows/github_linux_IaC 80 | ref: ${{ env.IAC_BRANCH }} 81 | 82 | # Uses dedicated restricted role and policy to enable this only for this task 83 | # No credentials are part of github for AWS auth 84 | - name: configure aws credentials 85 | uses: aws-actions/configure-aws-credentials@main 86 | with: 87 | role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }} 88 | role-session-name: ${{ secrets.AWS_ROLE_SESSION }} 89 | aws-region: ${{ env.AWS_REGION }} 90 | 91 | - name: DEBUG - Show IaC files 92 | if: env.ENABLE_DEBUG == 'true' 93 | run: | 94 | echo "OSVAR = $OSVAR" 95 | echo "benchmark_type = $benchmark_type" 96 | echo "PRIVSUBNET_ID = $AWS_PRIVSUBNET_ID" 97 | echo "VPC_ID" = $AWS_VPC_SECGRP_ID" 98 | pwd 99 | ls 100 | env: 101 | # Imported from GitHub variables this is used to load the relevant OS.tfvars file 102 | OSVAR: ${{ vars.OSVAR }} 103 | benchmark_type: ${{ vars.BENCHMARK_TYPE }} 104 | PRIVSUBNET_ID: ${{ secrets.AWS_PRIVSUBNET_ID }} 105 | VPC_ID: ${{ secrets.AWS_VPC_SECGRP_ID }} 106 | 107 | - name: Tofu init 108 | id: init 109 | run: tofu init 110 | env: 111 | # Imported from GitHub variables this is used to load the relevant OS.tfvars file 112 | OSVAR: ${{ vars.OSVAR }} 113 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 114 | 115 | - name: Tofu validate 116 | id: validate 117 | run: tofu validate 118 | env: 119 | # Imported from GitHub variables this is used to load the relevant OS.tfvars file 120 | OSVAR: ${{ vars.OSVAR }} 121 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 122 | 123 | - name: Tofu apply 124 | id: apply 125 | env: 126 | OSVAR: ${{ vars.OSVAR }} 127 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 128 | TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} 129 | TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} 130 | run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false 131 | 132 | ## Debug Section 133 | - name: DEBUG - Show Ansible hostfile 134 | if: env.ENABLE_DEBUG == 'true' 135 | run: cat hosts.yml 136 | 137 | # Aws deployments taking a while to come up insert sleep or playbook fails 138 | 139 | - name: Sleep to allow system to come up 140 | run: sleep ${{ vars.BUILD_SLEEPTIME }} 141 | 142 | # Run the Ansible playbook 143 | - name: Run_Ansible_Playbook 144 | env: 145 | ANSIBLE_HOST_KEY_CHECKING: "false" 146 | ANSIBLE_DEPRECATION_WARNINGS: "false" 147 | run: | 148 | /opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml 149 | 150 | # Remove test system - User secrets to keep if necessary 151 | 152 | - name: Tofu Destroy 153 | if: always() && env.ENABLE_DEBUG == 'false' 154 | env: 155 | OSVAR: ${{ vars.OSVAR }} 156 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 157 | TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} 158 | TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} 159 | run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false 160 | -------------------------------------------------------------------------------- /.github/workflows/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | profile = "" 3 | region = var.aws_region 4 | } 5 | 6 | // Create a security group with access to port 22 and port 80 open to serve HTTP traffic 7 | 8 | 9 | resource "random_id" "server" { 10 | keepers = { 11 | # Generate a new id each time we switch to a new AMI id 12 | ami_id = "${var.ami_id}" 13 | } 14 | 15 | byte_length = 8 16 | } 17 | 18 | resource "aws_security_group" "github_actions" { 19 | name = "${var.namespace}-${random_id.server.hex}-SG" 20 | vpc_id = aws_vpc.Main.id 21 | 22 | ingress { 23 | from_port = 22 24 | to_port = 22 25 | protocol = "tcp" 26 | cidr_blocks = ["0.0.0.0/0"] 27 | } 28 | 29 | ingress { 30 | from_port = 80 31 | to_port = 80 32 | protocol = "tcp" 33 | cidr_blocks = ["0.0.0.0/0"] 34 | } 35 | 36 | egress { 37 | from_port = 0 38 | to_port = 0 39 | protocol = "-1" 40 | cidr_blocks = ["0.0.0.0/0"] 41 | } 42 | tags = { 43 | Environment = "${var.environment}" 44 | Name = "${var.namespace}-SG" 45 | } 46 | } 47 | 48 | // instance setup 49 | 50 | resource "aws_instance" "testing_vm" { 51 | ami = var.ami_id 52 | availability_zone = var.availability_zone 53 | associate_public_ip_address = true 54 | key_name = var.ami_key_pair_name # This is the key as known in the ec2 key_pairs 55 | instance_type = var.instance_type 56 | tags = var.instance_tags 57 | vpc_security_group_ids = [aws_security_group.github_actions.id] 58 | subnet_id = aws_subnet.Main.id 59 | root_block_device { 60 | delete_on_termination = true 61 | } 62 | } 63 | 64 | // generate inventory file 65 | resource "local_file" "inventory" { 66 | filename = "./hosts.yml" 67 | directory_permission = "0755" 68 | file_permission = "0644" 69 | content = <> $GITHUB_ENV 56 | echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}" 57 | else 58 | echo IAC_BRANCH=main >> $GITHUB_ENV 59 | fi 60 | 61 | # Pull in terraform code for linux servers 62 | - name: Clone GitHub IaC plan 63 | uses: actions/checkout@v4 64 | with: 65 | repository: ansible-lockdown/github_linux_IaC 66 | path: .github/workflows/github_linux_IaC 67 | ref: ${{ env.IAC_BRANCH }} 68 | 69 | # Uses dedicated restricted role and policy to enable this only for this task 70 | # No credentials are part of github for AWS auth 71 | - name: configure aws credentials 72 | uses: aws-actions/configure-aws-credentials@main 73 | with: 74 | role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }} 75 | role-session-name: ${{ secrets.AWS_ROLE_SESSION }} 76 | aws-region: ${{ env.AWS_REGION }} 77 | 78 | - name: DEBUG - Show IaC files 79 | if: env.ENABLE_DEBUG == 'true' 80 | run: | 81 | echo "OSVAR = $OSVAR" 82 | echo "benchmark_type = $benchmark_type" 83 | echo "PRIVSUBNET_ID = $AWS_PRIVSUBNET_ID" 84 | echo "VPC_ID" = $AWS_VPC_SECGRP_ID" 85 | pwd 86 | ls 87 | env: 88 | # Imported from GitHub variables this is used to load the relevant OS.tfvars file 89 | OSVAR: ${{ vars.OSVAR }} 90 | benchmark_type: ${{ vars.BENCHMARK_TYPE }} 91 | PRIVSUBNET_ID: ${{ secrets.AWS_PRIVSUBNET_ID }} 92 | VPC_ID: ${{ secrets.AWS_VPC_SECGRP_ID }} 93 | 94 | - name: Tofu init 95 | id: init 96 | run: tofu init 97 | env: 98 | # Imported from GitHub variables this is used to load the relevant OS.tfvars file 99 | OSVAR: ${{ vars.OSVAR }} 100 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 101 | 102 | - name: Tofu validate 103 | id: validate 104 | run: tofu validate 105 | env: 106 | # Imported from GitHub variables this is used to load the relevant OS.tfvars file 107 | OSVAR: ${{ vars.OSVAR }} 108 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 109 | 110 | - name: Tofu apply 111 | id: apply 112 | env: 113 | OSVAR: ${{ vars.OSVAR }} 114 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 115 | TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} 116 | TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} 117 | run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false 118 | 119 | ## Debug Section 120 | - name: DEBUG - Show Ansible hostfile 121 | if: env.ENABLE_DEBUG == 'true' 122 | run: cat hosts.yml 123 | 124 | # Aws deployments taking a while to come up insert sleep or playbook fails 125 | 126 | - name: Sleep to allow system to come up 127 | run: sleep ${{ vars.BUILD_SLEEPTIME }} 128 | 129 | # Run the Ansible playbook 130 | - name: Run_Ansible_Playbook 131 | env: 132 | ANSIBLE_HOST_KEY_CHECKING: "false" 133 | ANSIBLE_DEPRECATION_WARNINGS: "false" 134 | run: | 135 | /opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml 136 | 137 | # Remove test system - User secrets to keep if necessary 138 | 139 | - name: Tofu Destroy 140 | if: always() && env.ENABLE_DEBUG == 'false' 141 | env: 142 | OSVAR: ${{ vars.OSVAR }} 143 | TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }} 144 | TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }} 145 | TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }} 146 | run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false 147 | -------------------------------------------------------------------------------- /.github/workflows/update_galaxy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: update galaxy 4 | 5 | on: 6 | push: 7 | branches: 8 | - main 9 | jobs: 10 | update_role: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout repo 14 | uses: actions/checkout@v4 15 | 16 | - name: Action Ansible Galaxy Release ${{ github.ref_name }} 17 | uses: ansible-actions/ansible-galaxy-action@main 18 | with: 19 | galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} 20 | -------------------------------------------------------------------------------- /.github/workflows/variables.tf: -------------------------------------------------------------------------------- 1 | // Taken from the OSname.tfvars 2 | 3 | variable "aws_region" { 4 | description = "AWS region" 5 | default = "us-east-1" 6 | type = string 7 | } 8 | 9 | variable "availability_zone" { 10 | description = "List of availability zone in the region" 11 | default = "us-east-1b" 12 | type = string 13 | } 14 | 15 | variable "instance_type" { 16 | description = "EC2 Instance Type" 17 | default = "t3.micro" 18 | type = string 19 | } 20 | 21 | variable "ami_key_pair_name" { 22 | description = "Name of key pair in AWS thats used" 23 | default = "Lockdown_enterprise_workflow-sshkey" 24 | type = string 25 | } 26 | 27 | variable "ami_os" { 28 | description = "AMI OS Type" 29 | type = string 30 | } 31 | 32 | variable "ami_id" { 33 | description = "AMI ID reference" 34 | type = string 35 | } 36 | 37 | variable "ami_username" { 38 | description = "Username for the ami id" 39 | type = string 40 | } 41 | 42 | variable "ami_user_home" { 43 | description = "home dir for the username" 44 | type = string 45 | } 46 | 47 | variable "namespace" { 48 | description = "Name used across all tags" 49 | default = "Lockdown_enterprise_workflow" 50 | type = string 51 | } 52 | 53 | variable "environment" { 54 | description = "Env Name used across all tags" 55 | type = string 56 | default = "Ansible_Lockdown_Environment" 57 | } 58 | 59 | variable "benchmark_os" { 60 | description = "The benchmark OS thats being tested" 61 | type = string 62 | } 63 | 64 | variable "benchmark_type" { 65 | description = "The benchmark OS thats being tested" 66 | type = string 67 | } 68 | 69 | variable "vpc_secgrp_id" { 70 | description = "The id of the vpc security group for the runner" 71 | type = string 72 | sensitive = true 73 | } 74 | 75 | variable "privsubnet_id" { 76 | description = "The id of the private subnet for the runner vpc" 77 | type = string 78 | sensitive = true 79 | } 80 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | *.log 3 | *.retry 4 | .vagrant 5 | tests/*redhat-subscription 6 | tests/Dockerfile 7 | *.iso 8 | *.box 9 | packer_cache 10 | delete* 11 | ignore* 12 | # VSCode 13 | .vscode 14 | vagrant 15 | 16 | # Byte-compiled / optimized / DLL files 17 | __pycache__/ 18 | *.py[cod] 19 | *$py.class 20 | 21 | # DS_Store 22 | .DS_Store 23 | ._* 24 | 25 | # Linux Editors 26 | *~ 27 | \#*\# 28 | /.emacs.desktop 29 | /.emacs.desktop.lock 30 | .elc 31 | auto-save-list 32 | tramp 33 | .\#* 34 | *.swp 35 | *.swo 36 | rh-creds.env 37 | travis.env 38 | 39 | # Lockdown-specific 40 | benchparse/ 41 | *xccdf.xml 42 | *.retry 43 | 44 | # GitHub Action/Workflow files 45 | .github/ 46 | 47 | # ansible-lint 48 | .ansible/ 49 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ##### CI for use by github no need for action to be added 3 | ##### Inherited 4 | ci: 5 | autofix_prs: false 6 | skip: [detect-aws-credentials, ansible-lint ] 7 | 8 | repos: 9 | - repo: https://github.com/pre-commit/pre-commit-hooks 10 | rev: v5.0.0 11 | hooks: 12 | # Safety 13 | - id: detect-aws-credentials 14 | - id: detect-private-key 15 | 16 | # git checks 17 | - id: check-merge-conflict 18 | - id: check-added-large-files 19 | - id: check-case-conflict 20 | 21 | # General checks 22 | - id: trailing-whitespace 23 | name: Trim Trailing Whitespace 24 | description: This hook trims trailing whitespace. 25 | entry: trailing-whitespace-fixer 26 | language: python 27 | types: [text] 28 | args: [--markdown-linebreak-ext=md] 29 | - id: end-of-file-fixer 30 | 31 | # Scan for passwords 32 | - repo: https://github.com/Yelp/detect-secrets 33 | rev: v1.5.0 34 | hooks: 35 | - id: detect-secrets 36 | 37 | - repo: https://github.com/gitleaks/gitleaks 38 | rev: v8.27.2 39 | hooks: 40 | - id: gitleaks 41 | 42 | - repo: https://github.com/ansible-community/ansible-lint 43 | rev: v25.5.0 44 | hooks: 45 | - id: ansible-lint 46 | name: Ansible-lint 47 | description: This hook runs ansible-lint. 48 | entry: python3 -m ansiblelint --force-color site.yml -c .ansible-lint 49 | language: python 50 | # do not pass files to ansible-lint, see: 51 | # https://github.com/ansible/ansible-lint/issues/611 52 | pass_filenames: false 53 | always_run: true 54 | additional_dependencies: 55 | # https://github.com/pre-commit/pre-commit/issues/1526 56 | # If you want to use specific version of ansible-core or ansible, feel 57 | # free to override `additional_dependencies` in your own hook config 58 | # file. 59 | - ansible-core>=2.10.1 60 | 61 | - repo: https://github.com/adrienverge/yamllint.git 62 | rev: v1.37.1 # or higher tag 63 | hooks: 64 | - id: yamllint 65 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | ignore: | 5 | tests/ 6 | molecule/ 7 | .github/ 8 | .gitlab-ci.yml 9 | *molecule.yml 10 | 11 | rules: 12 | indentation: 13 | # Requiring 4 space indentation 14 | spaces: 4 15 | # Requiring consistent indentation within a file, either indented or not 16 | indent-sequences: consistent 17 | braces: 18 | max-spaces-inside: 1 19 | level: error 20 | brackets: 21 | max-spaces-inside: 1 22 | level: error 23 | empty-lines: 24 | max: 1 25 | line-length: disable 26 | key-duplicates: enable 27 | new-line-at-end-of-file: enable 28 | new-lines: 29 | type: unix 30 | trailing-spaces: enable 31 | truthy: 32 | allowed-values: ['true', 'false'] 33 | check-keys: true 34 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | Contributing to MindPoint Group Projects 2 | ======================================== 3 | 4 | Rules 5 | ----- 6 | 1) All commits must be GPG signed (details in Signing section) 7 | 2) All commits must have Signed-off-by (Signed-off-by: Joan Doe ) in the commit message (details in Signing section) 8 | 3) All work is done in your own branch 9 | 4) All pull requests go into the devel branch. There are automated checks for signed commits, signoff in commit message, and functional testing) 10 | 5) Be open and nice to eachother 11 | 12 | Workflow 13 | -------- 14 | - Your work is done in your own individual branch. Make sure to to Signed-off and GPG sign all commits you intend to merge 15 | - All community Pull Requests are into the devel branch. There are automated checks for GPG signed, Signed-off in commits, and functional tests before being approved. If your pull request comes in from outside of our repo, the pull request will go into a staging branch. There is info needed from our repo for our CI/CD testing. 16 | - 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 17 | Signing your contribution 18 | ------------------------- 19 | 20 | We've chosen to use the Developer's Certificate of Origin (DCO) method 21 | that is employed by the Linux Kernel Project, which provides a simple 22 | way to contribute to MindPoint Group projects. 23 | 24 | The process is to certify the below DCO 1.1 text 25 | :: 26 | 27 | Developer's Certificate of Origin 1.1 28 | 29 | By making a contribution to this project, I certify that: 30 | 31 | (a) The contribution was created in whole or in part by me and I 32 | have the right to submit it under the open source license 33 | indicated in the file; or 34 | 35 | (b) The contribution is based upon previous work that, to the best 36 | of my knowledge, is covered under an appropriate open source 37 | license and I have the right under that license to submit that 38 | work with modifications, whether created in whole or in part 39 | by me, under the same open source license (unless I am 40 | permitted to submit under a different license), as indicated 41 | in the file; or 42 | 43 | (c) The contribution was provided directly to me by some other 44 | person who certified (a), (b) or (c) and I have not modified 45 | it. 46 | 47 | (d) I understand and agree that this project and the contribution 48 | are public and that a record of the contribution (including all 49 | personal information I submit with it, including my sign-off) is 50 | maintained indefinitely and may be redistributed consistent with 51 | this project or the open source license(s) involved. 52 | :: 53 | 54 | Then, when it comes time to submit a contribution, include the 55 | following text in your contribution commit message: 56 | 57 | :: 58 | 59 | Signed-off-by: Joan Doe 60 | 61 | :: 62 | 63 | 64 | This message can be entered manually, or if you have configured git 65 | with the correct `user.name` and `user.email`, you can use the `-s` 66 | option to `git commit` to automatically include the signoff message. 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ansible Lockdown 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Amazon 2 Linux 2 | 3 | Configure Amazon Linux 2 machine to be [CIS](https://www.cisecurity.org/cis-benchmarks/) compliant 4 | Untested on OEL 5 | 6 | Based on [CIS Amazon Linux 2 Benchmark v3.0.0 - 12-22-2023 ](https://www.cisecurity.org/cis-benchmarks/) 7 | 8 | 9 | ![Org Stars](https://img.shields.io/github/stars/ansible-lockdown?label=Org%20Stars&style=social) 10 | ![Stars](https://img.shields.io/github/stars/ansible-lockdown/AMAZON2-CIS?label=Repo%20Stars&style=social) 11 | ![Forks](https://img.shields.io/github/forks/ansible-lockdown/AMAZON2-CIS?style=social) 12 | ![followers](https://img.shields.io/github/followers/ansible-lockdown?style=social) 13 | [![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/AnsibleLockdown.svg?style=social&label=Follow%20%40AnsibleLockdown)](https://twitter.com/AnsibleLockdown) 14 | 15 | ![Discord Badge](https://img.shields.io/discord/925818806838919229?logo=discord) 16 | 17 | ![Release Branch](https://img.shields.io/badge/Release%20Branch-Main-brightgreen) 18 | ![Release Tag](https://img.shields.io/github/v/release/ansible-lockdown/AMAZON2-CIS) 19 | ![Release Date](https://img.shields.io/github/release-date/ansible-lockdown/AMAZON2-CIS) 20 | 21 | [![Main Pipeline Status](https://github.com/ansible-lockdown/AMAZON2-CIS/actions/workflows/main_pipeline_validation.yml/badge.svg?)](https://github.com/ansible-lockdown/AMAZON2-CIS/actions/workflows/main_pipeline_validation.yml) 22 | 23 | [![Devel Pipeline Status](https://github.com/ansible-lockdown/AMAZON2-CIS/actions/workflows/devel_pipeline_validation.yml/badge.svg?)](https://github.com/ansible-lockdown/AMAZON2-CIS/actions/workflows/devel_pipeline_validation.yml) 24 | ![Devel Commits](https://img.shields.io/github/commit-activity/m/ansible-lockdown/AMAZON2-CIS/devel?color=dark%20green&label=Devel%20Branch%20Commits) 25 | 26 | ![Issues Open](https://img.shields.io/github/issues-raw/ansible-lockdown/AMAZON2-CIS?label=Open%20Issues) 27 | ![Issues Closed](https://img.shields.io/github/issues-closed-raw/ansible-lockdown/AMAZON2-CIS?label=Closed%20Issues&&color=success) 28 | ![Pull Requests](https://img.shields.io/github/issues-pr/ansible-lockdown/AMAZON2-CIS?label=Pull%20Requests) 29 | 30 | ![License](https://img.shields.io/github/license/ansible-lockdown/AMAZON2-CIS?label=License) 31 | 32 | ## Join us 33 | 34 | On our [Discord Server](https://www.lockdownenterprise.com/discord) to ask questions, discuss features, or just chat with other Ansible-Lockdown users 35 | 36 | ## Caution(s) 37 | 38 | 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. 39 | 40 | Check Mode is not supported! The role will complete in check mode without errors, but it is not supported and should be used with caution. The AMAZON2-CIS-Audit role or a compliance scanner should be used for compliance checking over check mode. 41 | 42 | 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. 43 | 44 | To use release version please point to main branch and relevant release for the cis benchmark you wish to work with. 45 | 46 | ## Coming from a previous release 47 | 48 | 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. 49 | 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. 50 | 51 | Further details can be seen in the [Changelog](./ChangeLog.md) 52 | 53 | ## Documentation 54 | 55 | - [Getting Started](https://www.lockdownenterprise.com/docs/getting-started-with-lockdown) 56 | - [Customizing Roles](https://www.lockdownenterprise.com/docs/customizing-lockdown-enterprise) 57 | - [Per-Host Configuration](https://www.lockdownenterprise.com/docs/per-host-lockdown-enterprise-configuration) 58 | - [Getting the Most Out of the Role](https://www.lockdownenterprise.com/docs/get-the-most-out-of-lockdown-enterprise) 59 | - [Wiki](https://github.com/ansible-lockdown/AMAZON2-CIS/wiki) 60 | - [Repo GitHub Page](https://ansible-lockdown.github.io/AMAZON2-CIS/) 61 | 62 | ## Requirements 63 | 64 | **General:** 65 | 66 | - Basic knowledge of Ansible, below are some links to the Ansible documentation to help get started if you are unfamiliar with Ansible 67 | 68 | - [Main Ansible documentation page](https://docs.ansible.com) 69 | - [Ansible Getting Started](https://docs.ansible.com/ansible/latest/user_guide/intro_getting_started.html) 70 | - [Tower User Guide](https://docs.ansible.com/ansible-tower/latest/html/userguide/index.html) 71 | - [Ansible Community Info](https://docs.ansible.com/ansible/latest/community/index.html) 72 | - Functioning Ansible and/or Tower Installed, configured, and running. This includes all of the base Ansible/Tower configurations, needed packages installed, and infrastructure setup. 73 | - 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 or the [Main Variables Wiki Page](https://github.com/ansible-lockdown/AMAZON2-CIS/wiki/Main-Variables). 74 | 75 | **Technical Dependencies:** 76 | 77 | - Running Ansible/Tower setup (this role is tested against Ansible version 2.11.1 and newer) 78 | - Python3 Ansible run environment 79 | - python-def - First task sets up the prerequisites (Tag pre-reqs)for python3 and python2 (where required) 80 | - libselinux-python 81 | - python3-rpm (package used by py3 to use the rpm pkg) 82 | - jmespath 83 | 84 | ## Role Variables 85 | 86 | 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. These variables can be found [here](https://github.com/ansible-lockdown/AMAZON2-CIS/wiki/Main-Variables) in the Main Variables Wiki page. All variables are listed there along with descriptions. 87 | 88 | ## Tags 89 | 90 | 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. 91 | 92 | 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. 93 | 94 | ```sh 95 | tags: 96 | - level1 97 | - scored 98 | - avahi 99 | - services 100 | - patch 101 | - rule_2.2.4 102 | ``` 103 | 104 | ## Branches 105 | 106 | - **devel** - This is the default branch and the working development branch. Community pull requests will pull into this branch 107 | - **main** - This is the release branch 108 | - **all other branches** - Individual community member branches 109 | 110 | ## Community Contribution 111 | 112 | We encourage you (the community) to contribute to this role. Please read the rules below. 113 | 114 | - Your work is done in your own individual branch. Make sure to Signed-off and GPG sign all commits you intend to merge. 115 | - All community Pull Requests are pulled into the devel branch 116 | - Pull Requests into devel will confirm your commits have a GPG signature, Signed-off, and a functional test before being approved 117 | - 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 118 | 119 | ## Pipeline Testing 120 | 121 | uses: 122 | 123 | - ansible-core 2.12+ 124 | - ansible collections - pulls in the latest version based on requirements file 125 | - runs the audit using the devel branch 126 | - This is an automated test that occurs on pull requests into devel 127 | 128 | ## Support 129 | 130 | This is a community project at its core and will be managed as such. 131 | 132 | If you would are interested in dedicated support to assist or provide bespoke setups 133 | 134 | - [Ansible Counselor](https://www.mindpointgroup.com/products/ansible-counselor-on-demand-ansible-services-and-consulting/) 135 | - [Try us out](https://engage.mindpointgroup.com/try-ansible-counselor) 136 | 137 | ## Credits and Thanks 138 | 139 | Massive thanks to the fantastic community and all its members. 140 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | host_key_checking=False 3 | display_skipped_hosts=True 4 | system_warnings=False 5 | command_warnings=False 6 | nocows=1 7 | retry_files_save_path=/dev/null 8 | pipelining=true 9 | 10 | # Use the YAML callback plugin. 11 | stdout_callback = yaml 12 | # Use the stdout_callback when running ad-hoc commands. 13 | #bin_ansible_callbacks = True 14 | 15 | 16 | [privilege_escalation] 17 | 18 | [paramiko_connection] 19 | record_host_keys=False 20 | 21 | [ssh_connection] 22 | transfer_method=scp 23 | ssh_args = -o ControlMaster=auto -o ControlPersist=60s 24 | 25 | [accelerate] 26 | 27 | [selinux] 28 | 29 | [colors] 30 | 31 | [diff] 32 | -------------------------------------------------------------------------------- /collections/requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | collections: 4 | 5 | - name: community.general 6 | source: https://github.com/ansible-collections/community.general 7 | type: git 8 | 9 | - name: community.crypto 10 | source: https://github.com/ansible-collections/community.crypto 11 | type: git 12 | 13 | - name: ansible.posix 14 | source: https://github.com/ansible-collections/ansible.posix 15 | type: git 16 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: systemd restart tmp.mount 4 | ansible.builtin.systemd: 5 | name: tmp.mount 6 | daemon_reload: true 7 | enabled: true 8 | masked: false 9 | state: reloaded 10 | 11 | - name: Remount dev_shm 12 | ansible.posix.mount: 13 | name: /dev/shm 14 | state: remounted 15 | 16 | - name: Remount home 17 | ansible.posix.mount: 18 | name: /home 19 | state: remounted 20 | 21 | - name: Remount var 22 | ansible.posix.mount: 23 | name: /var 24 | state: remounted 25 | 26 | - name: Remount var_tmp 27 | ansible.posix.mount: 28 | name: /var/tmp 29 | state: remounted 30 | 31 | - name: Remount var_log 32 | ansible.posix.mount: 33 | name: /var/log 34 | state: remounted 35 | 36 | - name: Remount var_log_audit 37 | ansible.posix.mount: 38 | name: /var/log/audit 39 | state: remounted 40 | 41 | - name: Systemd_daemon_reload 42 | ansible.builtin.systemd: 43 | daemon_reload: true 44 | 45 | - name: Rebuild_grub 46 | ansible.builtin.command: /sbin/grub2-mkconfig -o "{{ amazon2cis_bootloader_file }}" 47 | 48 | - name: Restart_postfix 49 | ansible.builtin.service: 50 | name: postfix 51 | state: restarted 52 | 53 | - name: Sysctl_flush_ipv4_routes 54 | ansible.posix.sysctl: 55 | name: net.ipv4.route.flush 56 | value: '1' 57 | sysctl_set: true 58 | ignore_errors: true # noqa ignore-errors 59 | 60 | - name: Sysctl_flush_ipv6_routes 61 | ansible.posix.sysctl: 62 | name: net.ipv6.route.flush 63 | value: '1' 64 | sysctl_set: true 65 | ignore_errors: true # noqa ignore-errors 66 | 67 | - name: Restart_rsyslog 68 | ansible.builtin.service: 69 | name: rsyslog 70 | state: restarted 71 | 72 | - name: Restart_journald 73 | ansible.builtin.service: 74 | name: systemd-journald 75 | state: restarted 76 | 77 | - name: Restart_systemd_journal_upload 78 | ansible.builtin.service: 79 | name: systemd-journal-upload 80 | state: restarted 81 | 82 | - name: update auditd 83 | ansible.builtin.template: 84 | src: audit/99_auditd.rules.j2 85 | dest: /etc/audit/rules.d/99_auditd.rules 86 | owner: root 87 | group: root 88 | mode: 0600 89 | notify: Restart_auditd 90 | 91 | - name: Auditd_immutable_check 92 | ansible.builtin.shell: grep -c "^-e 2" /etc/audit/rules.d/99_auditd.rules 93 | changed_when: false 94 | register: auditd_immutable_check 95 | 96 | - name: Audit_immutable_fact 97 | ansible.builtin.debug: 98 | msg: "Reboot required for auditd to apply new rules as immutable set" 99 | notify: Change_requires_reboot 100 | when: 101 | - auditd_immutable_check.stdout == '1' 102 | 103 | - name: Restart_auditd 104 | ansible.builtin.shell: /sbin/service auditd restart 105 | 106 | - name: grub2cfg 107 | ansible.builtin.command: /sbin/grub2-mkconfig -o "{{ amazon2cis_bootloader_file }}" 108 | notify: Change_requires_reboot 109 | 110 | - name: restart rsyslog 111 | ansible.builtin.service: 112 | name: rsyslog 113 | state: restarted 114 | 115 | - name: restart sshd 116 | ansible.builtin.service: 117 | name: sshd 118 | state: restarted 119 | 120 | - name: Change_requires_reboot 121 | ansible.builtin.set_fact: 122 | change_requires_reboot: true 123 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | galaxy_info: 4 | author: "George Nalen, Mark Bolwell" 5 | description: "Apply the Amazon Linux 2 CIS controls" 6 | company: "MindPoint Group" 7 | license: MIT 8 | namespace: mindpointgroup 9 | role_name: amazon2_cis 10 | min_ansible_version: 2.11.1 11 | platforms: 12 | - name: Amazon Linux 13 | versions: 14 | - "2" 15 | galaxy_tags: 16 | - system 17 | - security 18 | - cis 19 | - hardening 20 | - benchmark 21 | - compliance 22 | - amazonlinux 23 | - complianceascode 24 | collections: 25 | - community.general 26 | - community.crypto 27 | - ansible.posix 28 | dependencies: [] 29 | -------------------------------------------------------------------------------- /site.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Run the ansible-lockdown remediation role 3 | hosts: all 4 | become: true 5 | 6 | roles: 7 | - role: "{{ playbook_dir }}" 8 | -------------------------------------------------------------------------------- /tasks/LE_audit_setup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Pre Audit Setup | Set audit package name 4 | block: 5 | - name: Pre Audit Setup | Set audit package name | 64bit 6 | ansible.builtin.set_fact: 7 | audit_pkg_arch_name: AMD64 8 | when: ansible_facts.machine == "x86_64" 9 | 10 | - name: Pre Audit Setup | Set audit package name | ARM64 11 | ansible.builtin.set_fact: 12 | audit_pkg_arch_name: ARM64 13 | when: ansible_facts.machine == "arm64" 14 | 15 | - name: Pre Audit Setup | Download audit binary 16 | ansible.builtin.get_url: 17 | url: "{{ audit_bin_url }}{{ audit_pkg_arch_name }}" 18 | dest: "{{ audit_bin }}" 19 | owner: root 20 | group: root 21 | checksum: "{{ audit_bin_version[audit_pkg_arch_name + '_checksum'] }}" 22 | mode: '0555' 23 | when: 24 | - get_audit_binary_method == 'download' 25 | 26 | - name: Pre Audit Setup | Copy audit binary 27 | ansible.builtin.copy: 28 | src: "{{ audit_bin_copy_location }}" 29 | dest: "{{ audit_bin }}" 30 | mode: '0555' 31 | owner: root 32 | group: root 33 | when: 34 | - get_audit_binary_method == 'copy' 35 | -------------------------------------------------------------------------------- /tasks/audit_only.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Audit_only | Show Audit Summary 4 | when: 5 | - audit_only 6 | ansible.builtin.debug: 7 | msg: "{{ audit_results.split('\n') }}" 8 | 9 | - name: Audit_only | Stop Playbook Audit Only selected 10 | when: 11 | - audit_only 12 | ansible.builtin.meta: end_play 13 | -------------------------------------------------------------------------------- /tasks/auditd.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: POST | AUDITD | Apply auditd template - only required rules will be added 4 | ansible.builtin.template: 5 | src: audit/99_auditd.rules.j2 6 | dest: /etc/audit/rules.d/99_auditd.rules 7 | owner: root 8 | group: root 9 | mode: 0600 10 | register: audit_rules_updated 11 | notify: 12 | - Auditd_immutable_check 13 | - Audit_immutable_fact 14 | - Restart_auditd 15 | -------------------------------------------------------------------------------- /tasks/check_prereqs.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "PREREQ | Add the required packages installed | Python2" 4 | ansible.builtin.package: 5 | name: "{{ item }}" 6 | state: latest 7 | register: python2_packages 8 | with_items: 9 | - python2-rpm 10 | - libselinux-python 11 | vars: 12 | ansible_python_interpreter: "{{ python2_bin }}" 13 | 14 | - name: "PREREQ | Check required packages installed | Python3 " 15 | ansible.builtin.package: 16 | name: "{{ item }}" 17 | state: present 18 | register: python3reqs_installed 19 | with_items: 20 | - python3-rpm 21 | when: 22 | - ansible_python.version.major is version('3', '=') 23 | vars: 24 | ansible_python_interpreter: "{{ python2_bin }}" 25 | -------------------------------------------------------------------------------- /tasks/fetch_audit_output.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Stage to copy audit output to a centralised location 4 | 5 | - name: "FETCH_AUDIT_FILES | Fetch files and copy to controller" 6 | when: audit_output_collection_method == "fetch" 7 | ansible.builtin.fetch: 8 | src: "{{ item }}" 9 | dest: "{{ audit_output_destination }}" 10 | flat: true 11 | failed_when: false 12 | register: discovered_audit_fetch_state 13 | loop: 14 | - "{{ pre_audit_outfile }}" 15 | - "{{ post_audit_outfile }}" 16 | become: false 17 | 18 | # Added this option for continuity but could be changed by adjusting the variable audit_conf_dest 19 | # Allowing backup to one location 20 | - name: "FETCH_AUDIT_FILES | Copy files to location available to managed node" 21 | when: audit_output_collection_method == "copy" 22 | ansible.builtin.copy: 23 | src: "{{ item }}" 24 | dest: "{{ audit_output_destination }}" 25 | mode: 'u-x,go-wx' 26 | flat: true 27 | failed_when: false 28 | register: discovered_audit_fetch_copy_state 29 | loop: 30 | - pre_audit_outfile 31 | - post_audit_outfile 32 | 33 | - name: "FETCH_AUDIT_FILES | Fetch files and copy to controller | Warning if issues with fetch_audit_files" 34 | when: 35 | - (audit_output_collection_method == "fetch" and not discovered_audit_fetch_state.changed) or 36 | (audit_output_collection_method == "copy" and not discovered_audit_copy_state.changed) 37 | block: 38 | - name: "FETCH_AUDIT_FILES | Fetch files and copy to controller | Warning if issues with fetch_audit_files" 39 | ansible.builtin.debug: 40 | msg: "Warning!! Unable to write to localhost {{ audit_output_destination }} for audit file copy" 41 | 42 | - name: "FETCH_AUDIT_FILES | Fetch files and copy to controller | Warning if issues with fetch_audit_files" 43 | vars: 44 | warn_control_id: "FETCH_AUDIT_FILES" 45 | ansible.builtin.import_tasks: 46 | file: warning_facts.yml 47 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Check OS version and family 4 | when: 5 | - os_check 6 | ansible.builtin.assert: 7 | that: (ansible_facts.distribution == 'Amazon' and ansible_facts.distribution_major_version is version_compare('2', '==')) 8 | fail_msg: "This role can only be run against Supported OSs. {{ ansible_facts.distribution }} {{ ansible_facts.distribution_major_version }} is not supported." 9 | success_msg: "This role is running against a supported OS {{ ansible_facts.distribution }} {{ ansible_facts.distribution_major_version }}" 10 | tags: 11 | - always 12 | 13 | - name: Check ansible version 14 | ansible.builtin.assert: 15 | that: ansible_version.full is version_compare(min_ansible_version, '>=') 16 | fail_msg: "You must use Ansible {{ min_ansible_version }} or greater" 17 | success_msg: "This role is running a supported version of ansible {{ ansible_version.full }} >= {{ min_ansible_version }}" 18 | tags: 19 | - always 20 | 21 | - name: Ensure root password is set 22 | when: 23 | - amazon2cis_rule_4_5_2_4 24 | tags: 25 | - always 26 | block: 27 | - name: Ensure root password is set 28 | ansible.builtin.shell: passwd -S root | egrep -e "(Password set, SHA512 crypt|Password locked)" 29 | changed_when: false 30 | failed_when: false 31 | register: root_passwd_set 32 | 33 | - name: Ensure root password is set 34 | ansible.builtin.assert: 35 | that: root_passwd_set.rc == 0 36 | fail_msg: "You have rule 4.5.2.4 enabled this requires that you have a root password set" 37 | success_msg: "You have a root password set" 38 | 39 | - name: "check sugroup exists if used" 40 | block: 41 | - name: "Check su group exists if defined" 42 | ansible.builtin.command: grep -w "{{ amazon2cis_sugroup }}" /etc/group 43 | changed_when: false 44 | failed_when: sugroup_exists.rc >= 2 45 | register: sugroup_exists 46 | 47 | - name: Check sugroup if defined exists before continuing 48 | ansible.builtin.assert: 49 | that: sugroup_exists.rc == 0 50 | msg: "The variable amazon2cis_sugroup is defined but does not exist please rectify" 51 | when: 52 | - amazon2cis_sugroup is defined 53 | - amazon2cis_rule_4_3_7 54 | tags: 55 | - rule_4.3.7 56 | 57 | - name: Run pre-reqs 58 | ansible.builtin.import_tasks: 59 | file: check_prereqs.yml 60 | tags: 61 | - always 62 | - prereqs 63 | 64 | - name: Run prelim tasks 65 | ansible.builtin.import_tasks: 66 | file: prelim.yml 67 | tags: 68 | - prelim_tasks 69 | - always 70 | 71 | - name: Gather the package facts 72 | ansible.builtin.package_facts: 73 | manager: auto 74 | tags: 75 | - always 76 | 77 | - name: Import section 1 tasks 78 | ansible.builtin.import_tasks: 79 | file: section_1/main.yml 80 | when: amazon2cis_section1 81 | tags: 82 | - amazon2cis_section1 83 | 84 | - name: Import section 2 tasks 85 | ansible.builtin.import_tasks: 86 | file: section_2/main.yml 87 | when: amazon2cis_section2 88 | tags: 89 | - amazon2cis_section2 90 | 91 | - name: Import section 3 tasks 92 | ansible.builtin.import_tasks: 93 | file: section_3/main.yml 94 | when: amazon2cis_section3 95 | tags: 96 | - amazon2cis_section3 97 | 98 | - name: Import section 4 tasks 99 | ansible.builtin.import_tasks: 100 | file: section_4/main.yml 101 | when: amazon2cis_section4 102 | tags: 103 | - amazon2cis_section4 104 | 105 | - name: Import section 5 tasks 106 | ansible.builtin.import_tasks: 107 | file: section_5/main.yml 108 | when: amazon2cis_section5 109 | tags: 110 | - amazon2cis_section5 111 | 112 | - name: Import section 6 tasks 113 | ansible.builtin.import_tasks: 114 | file: section_6/main.yml 115 | when: amazon2cis_section6 116 | tags: 117 | - amazon2cis_section6 118 | 119 | - name: Run auditd logic 120 | when: 121 | - update_audit_template 122 | tags: 123 | - always 124 | ansible.builtin.import_tasks: 125 | file: auditd.yml 126 | 127 | - name: Run post remediation tasks 128 | tags: 129 | - post_tasks 130 | - always 131 | ansible.builtin.import_tasks: 132 | file: post.yml 133 | 134 | - name: Run post_remediation audit 135 | when: 136 | - run_audit 137 | tags: 138 | - run_audit 139 | ansible.builtin.import_tasks: 140 | file: post_remediation_audit.yml 141 | 142 | - name: Add ansible file showing Benchmark and levels applied 143 | block: 144 | - name: Create ansible facts directory 145 | ansible.builtin.file: 146 | path: "{{ ansible_facts_path }}" 147 | state: directory 148 | owner: root 149 | group: root 150 | mode: 'u=rwx,go=rx' 151 | 152 | - name: Create ansible facts file 153 | ansible.builtin.template: 154 | src: etc/ansible/compliance_facts.j2 155 | dest: "{{ ansible_facts_path }}/compliance_facts.fact" 156 | owner: root 157 | group: root 158 | mode: "u-x,go-wx" 159 | when: 160 | - create_benchmark_facts 161 | - (post_audit_summary is defined) or 162 | (ansible_local['compliance_facts']['lockdown_audit_details']['audit_summary'] is undefined and post_audit_summary is undefined) 163 | tags: 164 | - always 165 | - benchmark 166 | 167 | - name: Fetch audit files 168 | ansible.builtin.import_tasks: 169 | file: fetch_audit_output.yml 170 | when: 171 | - fetch_audit_output 172 | - run_audit 173 | tags: always 174 | 175 | - name: Show Audit Summary 176 | when: 177 | - run_audit 178 | tags: 179 | - run_audit 180 | ansible.builtin.debug: 181 | msg: "{{ audit_results.split('\n') }}" 182 | 183 | - name: Output Warning count and control IDs affected 184 | tags: 185 | - always 186 | ansible.builtin.debug: 187 | msg: "You have {{ warn_count }} warning(s) that require investigating that are related to the following benchmark ID(s) {{ warn_control_list }}" 188 | -------------------------------------------------------------------------------- /tasks/parse_etc_password.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "PRELIM | Parse Password Entries | Parse /etc/passwd" 3 | block: 4 | - name: "PRELIM | Parse /etc/passwd" 5 | ansible.builtin.command: cat /etc/passwd 6 | changed_when: false 7 | failed_when: false 8 | check_mode: false 9 | register: amazon2cis_passwd_file_audit 10 | 11 | - name: "PRELIM | Parse Password EntriesSplit passwd entries" 12 | ansible.builtin.set_fact: 13 | amazon2cis_passwd: "{{ amazon2cis_passwd_file_audit.stdout_lines | map('regex_replace', ld_passwd_regex, ld_passwd_yaml) | map('from_yaml') | list }}" 14 | with_items: 15 | - "{{ amazon2cis_passwd_file_audit.stdout_lines }}" 16 | vars: 17 | ld_passwd_regex: >- 18 | ^(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*):(?P[^:]*) 19 | ld_passwd_yaml: | # pragma: allowlist secret 20 | id: >-4 21 | \g 22 | password: >-4 23 | \g 24 | uid: \g 25 | gid: \g 26 | gecos: >-4 27 | \g 28 | dir: >-4 29 | \g 30 | shell: >-4 31 | \g 32 | tags: 33 | - always 34 | -------------------------------------------------------------------------------- /tasks/post.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Post tasks 3 | 4 | - name: POST | Perform yum package cleanup 5 | ansible.builtin.package: 6 | autoremove: true 7 | changed_when: false 8 | 9 | - name: POST | flush handlers 10 | ansible.builtin.meta: flush_handlers 11 | 12 | - name: POST | reboot system if changes require it and not skipped 13 | block: 14 | - name: POST | Reboot system if changes require it and not skipped 15 | when: 16 | - reboot_required 17 | - not skip_reboot 18 | ansible.builtin.reboot: 19 | 20 | - name: POST | Warning a reboot required but skip option set 21 | when: 22 | - reboot_required 23 | - skip_reboot 24 | ansible.builtin.debug: 25 | msg: "Warning!! changes have been made that require a reboot to be implemented but skip reboot was set - Can affect compliance check results" 26 | changed_when: true 27 | 28 | - name: "POST | Warning a reboot required but skip option set | warning count" 29 | when: 30 | - reboot_required 31 | - skip_reboot 32 | ansible.builtin.import_tasks: 33 | file: warning_facts.yml 34 | vars: 35 | warn_control_id: Reboot_required 36 | tags: 37 | - always 38 | 39 | - name: If Warning count is 0 set fact 40 | when: 41 | - warn_count == '0' 42 | ansible.builtin.set_fact: 43 | control_number: "Congratulation None Found" 44 | -------------------------------------------------------------------------------- /tasks/post_remediation_audit.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Post Audit | Run post_remediation {{ benchmark }} audit 4 | ansible.builtin.shell: "{{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -o {{ post_audit_outfile }} -g \"{{ group_names }}\"" 5 | changed_when: true 6 | environment: 7 | AUDIT_BIN: "{{ audit_bin }}" 8 | AUDIT_CONTENT_LOCATION: "{{ audit_conf_dest | default('/opt') }}" 9 | AUDIT_FILE: goss.yml 10 | 11 | - name: Post Audit | Ensure audit files readable by users 12 | ansible.builtin.file: 13 | path: "{{ item }}" 14 | mode: '0644' 15 | state: file 16 | loop: 17 | - "{{ post_audit_outfile }}" 18 | - "{{ pre_audit_outfile }}" 19 | 20 | - name: Post Audit | Capture audit data if json format 21 | when: 22 | - audit_format == "json" 23 | block: 24 | - name: Post Audit | Capture audit data if json format 25 | ansible.builtin.shell: grep -E '"summary-line.*Count:.*Failed' "{{ post_audit_outfile }}" | cut -d'"' -f4 26 | register: post_audit_summary 27 | changed_when: false 28 | 29 | - name: Post Audit | Set Fact for audit summary 30 | ansible.builtin.set_fact: 31 | post_audit_results: "{{ post_audit_summary.stdout }}" 32 | 33 | - name: Post Audit | Capture audit data if documentation format 34 | when: 35 | - audit_format == "documentation" 36 | block: 37 | - name: Post Audit | Capture audit data if documentation format 38 | ansible.builtin.shell: "tail -2 {{ post_audit_outfile }}" 39 | register: post_audit_summary 40 | changed_when: false 41 | 42 | - name: Post Audit | Set Fact for audit summary 43 | ansible.builtin.set_fact: 44 | post_audit_results: "{{ post_audit_summary.stdout }}" 45 | -------------------------------------------------------------------------------- /tasks/pre_remediation_audit.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Pre Audit Setup | Setup the LE audit 4 | when: 5 | - setup_audit 6 | tags: 7 | - setup_audit 8 | ansible.builtin.include_tasks: 9 | file: LE_audit_setup.yml 10 | 11 | - name: Pre Audit Setup | Ensure {{ audit_conf_dir }} exists 12 | ansible.builtin.file: 13 | path: "{{ audit_conf_dir }}" 14 | state: directory 15 | mode: '0755' 16 | 17 | - name: Pre Audit Setup | If using git for content set up 18 | when: 19 | - audit_content == 'git' 20 | block: 21 | - name: Pre Audit Setup | Install git 22 | ansible.builtin.package: 23 | name: git 24 | state: present 25 | 26 | - name: Pre Audit Setup | Retrieve audit content files from git 27 | ansible.builtin.git: 28 | repo: "{{ audit_file_git }}" 29 | dest: "{{ audit_conf_dir }}" 30 | version: "{{ audit_git_version }}" 31 | 32 | - name: Pre Audit Setup | Copy to audit content files to server 33 | when: 34 | - audit_content == 'copy' 35 | ansible.builtin.copy: 36 | src: "{{ audit_conf_source }}" 37 | dest: "{{ audit_conf_dest }}" 38 | mode: preserve 39 | 40 | - name: Pre Audit Setup | Unarchive audit content files on server 41 | when: 42 | - audit_content == 'archive' 43 | ansible.builtin.unarchive: 44 | src: "{{ audit_conf_source }}" 45 | dest: "{{ audit_conf_dest }}" 46 | 47 | - name: Pre Audit Setup | Get audit content from url 48 | when: 49 | - audit_content == 'get_url' 50 | ansible.builtin.unarchive: 51 | src: "{{ audit_conf_source }}" 52 | dest: "{{ audit_conf_dest }}/{{ benchmark }}-Audit" 53 | remote_src: "{{ ( audit_conf_source is contains ('http'))| ternary(true, false ) }}" 54 | extra_opts: "{{ (audit_conf_source is contains ('github')) | ternary('--strip-components=1', [] ) }}" 55 | 56 | - name: Pre Audit Setup | Check Goss is available 57 | when: 58 | - run_audit 59 | block: 60 | - name: Pre Audit Setup | Check for goss file 61 | ansible.builtin.stat: 62 | path: "{{ audit_bin }}" 63 | register: discovered_goss_available 64 | 65 | - name: Pre Audit Setup | If audit ensure goss is available 66 | ansible.builtin.assert: 67 | that: discovered_goss_available.stat.exists 68 | msg: "Audit has been selected: unable to find goss binary at {{ audit_bin }}" 69 | 70 | - name: Pre Audit Setup | Copy ansible default vars values to test audit 71 | when: 72 | - run_audit 73 | tags: 74 | - goss_template 75 | - run_audit 76 | ansible.builtin.template: 77 | src: ansible_vars_goss.yml.j2 78 | dest: "{{ audit_vars_path }}" 79 | mode: '0600' 80 | 81 | - name: Pre Audit | Run pre_remediation {{ benchmark }} audit 82 | ansible.builtin.shell: "{{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -o {{ pre_audit_outfile }} -g \"{{ group_names }}\"" 83 | changed_when: true 84 | environment: 85 | AUDIT_BIN: "{{ audit_bin }}" 86 | AUDIT_CONTENT_LOCATION: "{{ audit_conf_dest | default('/opt') }}" 87 | AUDIT_FILE: goss.yml 88 | 89 | - name: Pre Audit | Capture audit data if json format 90 | when: 91 | - audit_format == "json" 92 | block: 93 | - name: Pre Audit | Capture audit data if json format 94 | ansible.builtin.shell: grep -E '\"summary-line.*Count:.*Failed' "{{ pre_audit_outfile }}" | cut -d'"' -f4 95 | register: pre_audit_summary 96 | changed_when: false 97 | 98 | - name: Pre Audit | Set Fact for audit summary 99 | ansible.builtin.set_fact: 100 | pre_audit_results: "{{ pre_audit_summary.stdout }}" 101 | 102 | - name: Pre Audit | Capture audit data if documentation format 103 | when: 104 | - audit_format == "documentation" 105 | block: 106 | - name: Pre Audit | Capture audit data if documentation format 107 | ansible.builtin.shell: tail -2 "{{ pre_audit_outfile }}" | tac | tr '\n' ' ' 108 | register: pre_audit_summary 109 | changed_when: false 110 | 111 | - name: Pre Audit | Set Fact for audit summary 112 | ansible.builtin.set_fact: 113 | pre_audit_results: "{{ pre_audit_summary.stdout }}" 114 | 115 | - name: Audit_Only | Run Audit Only 116 | when: 117 | - audit_only 118 | ansible.builtin.import_tasks: 119 | file: audit_only.yml 120 | -------------------------------------------------------------------------------- /tasks/section_1/cis_1.1.2.1.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "1.1.2.1.1 | PATCH | Ensure /tmp is a seperate partition" 4 | when: 5 | - required_mount not in mount_names 6 | - amazon2cis_rule_1_1_2_1_1 7 | tags: 8 | - level1 9 | - automated 10 | - patch 11 | - rule_1.1.2.1.1 12 | - mounts 13 | - NIST800-53R5_CM-7 14 | vars: 15 | warn_control_id: '1.1.2.1.1' 16 | required_mount: '/tmp' 17 | block: 18 | - name: "1.1.2.1.1 | AUDIT | Ensure /tmp is a separate partition | Absent" 19 | ansible.builtin.debug: 20 | msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" 21 | 22 | - name: "1.1.2.1.1 | AUDIT | Ensure /tmp is a separate partition | Warn Count" 23 | ansible.builtin.import_tasks: 24 | file: warning_facts.yml 25 | 26 | - name: | 27 | "1.1.2.1.2 | PATCH | Ensure nodev option set on /tmp partition 28 | 1.1.2.1.3 | PATCH | Ensure nosuid option set on /tmp partition 29 | 1.1.2.1.4 | PATCH | Ensure noexec option set on /tmp partition" 30 | when: 31 | - item.mount == "/tmp" 32 | - amazon2cis_tmp_svc 33 | - amazon2cis_rule_1_1_2_1_2 or 34 | amazon2cis_rule_1_1_2_1_3 or 35 | amazon2cis_rule_1_1_2_1_4 36 | tags: 37 | - level1 38 | - automated 39 | - patch 40 | - rule_1.1.2.1.2 41 | - rule_1.1.2.1.3 42 | - rule_1.1.2.1.4 43 | - mounts 44 | - NIST800-53R5_AC-3 45 | - NIST800-53R5_MP-2 46 | ansible.posix.mount: 47 | name: /tmp 48 | src: "{{ item.device }}" 49 | fstype: "{{ item.fstype }}" 50 | state: present 51 | opts: defaults,{% if amazon2cis_rule_1_1_2_1_2 %}nodev,{% endif %}{% if amazon2cis_rule_1_1_2_1_3 %}nosuid,{% endif %}{% if amazon2cis_rule_1_1_2_1_4 %}noexec{% endif %} 52 | notify: systemd restart tmp.mount 53 | with_items: 54 | - "{{ ansible_mounts }}" 55 | loop_control: 56 | label: "{{ item.device }}" 57 | -------------------------------------------------------------------------------- /tasks/section_1/cis_1.1.2.2.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "1.1.2.2.1 | PATCH | Ensure /dev/shm is a seperate partition" 4 | when: 5 | - required_mount not in mount_names 6 | - amazon2cis_rule_1_1_2_2_1 7 | tags: 8 | - level1 9 | - automated 10 | - patch 11 | - rule_1.1.2.2.1 12 | - mounts 13 | - NIST800-53R5_CM-7 14 | vars: 15 | warn_control_id: '1.1.2.2.1' 16 | required_mount: '/dev/shm' 17 | block: 18 | - name: "1.1.2.2.1 | AUDIT | Ensure /dev/shm is a separate partition | Absent" 19 | ansible.builtin.debug: 20 | msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" 21 | 22 | - name: "1.1.2.2.1 | AUDIT | Ensure /dev/shm is a separate partition | Warn Count" 23 | ansible.builtin.import_tasks: 24 | file: warning_facts.yml 25 | 26 | - name: | 27 | "1.1.2.2.2 | PATCH | Ensure nodev option set on /dev/shm partition 28 | 1.1.2.2.3 | PATCH | Ensure nosuid option set on /dev/shm partition 29 | 1.1.2.2.4 | PATCH | Ensure noexec option set on /dev/shm partition" 30 | when: 31 | - item.mount == "/dev/shm" 32 | - amazon2cis_tmp_svc 33 | - amazon2cis_rule_1_1_2_2_2 or 34 | amazon2cis_rule_1_1_2_2_3 or 35 | amazon2cis_rule_1_1_2_2_4 36 | tags: 37 | - level1 38 | - automated 39 | - patch 40 | - rule_1.1.2.2.2 41 | - rule_1.1.2.2.3 42 | - rule_1.1.2.2.4 43 | - mounts 44 | - NIST800-53R5_AC-3 45 | - NIST800-53R5_MP-2 46 | ansible.posix.mount: 47 | name: /dev/shm 48 | src: "{{ item.device }}" 49 | fstype: "{{ item.fstype }}" 50 | state: present 51 | opts: defaults,{% if amazon2cis_rule_1_1_2_2_2 %}nodev,{% endif %}{% if amazon2cis_rule_1_1_2_2_3 %}nosuid,{% endif %}{% if amazon2cis_rule_1_1_2_2_4 %}noexec{% endif %} 52 | notify: Remount dev_shm 53 | with_items: 54 | - "{{ ansible_mounts }}" 55 | loop_control: 56 | label: "{{ item.device }}" 57 | -------------------------------------------------------------------------------- /tasks/section_1/cis_1.1.2.3.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "1.1.2.3.1 | PATCH | Ensure /home is a seperate partition" 4 | when: 5 | - required_mount not in mount_names 6 | - amazon2cis_rule_1_1_2_3_1 7 | tags: 8 | - level2 9 | - automated 10 | - patch 11 | - rule_1.1.2.3.1 12 | - mounts 13 | - NIST800-53R5_CM-7 14 | vars: 15 | warn_control_id: '1.1.2.3.1' 16 | required_mount: '/home' 17 | block: 18 | - name: "1.1.2.3.1 | AUDIT | Ensure /home is a separate partition | Absent" 19 | ansible.builtin.debug: 20 | msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" 21 | 22 | - name: "1.1.2.3.1 | AUDIT | Ensure /home is a separate partition | Warn Count" 23 | ansible.builtin.import_tasks: 24 | file: warning_facts.yml 25 | 26 | - name: | 27 | "1.1.2.3.2 | PATCH | Ensure nodev option set on /home partition 28 | 1.1.2.3.3 | PATCH | Ensure nosuid option set on /home partition" 29 | when: 30 | - item.mount == "/home" 31 | - amazon2cis_tmp_svc 32 | - amazon2cis_rule_1_1_2_3_2 or 33 | amazon2cis_rule_1_1_2_3_3 34 | tags: 35 | - level1 36 | - automated 37 | - patch 38 | - rule_1.1.2.3.2 39 | - rule_1.1.2.3.3 40 | - mounts 41 | - NIST800-53R5_AC-3 42 | - NIST800-53R5_MP-2 43 | ansible.posix.mount: 44 | name: /home 45 | src: "{{ item.device }}" 46 | fstype: "{{ item.fstype }}" 47 | state: present 48 | opts: defaults,{% if amazon2cis_rule_1_1_2_3_2 %}nodev,{% endif %}{% if amazon2cis_rule_1_1_2_3_3 %}nosuid{% endif %} 49 | notify: Remount home 50 | with_items: 51 | - "{{ ansible_mounts }}" 52 | loop_control: 53 | label: "{{ item.device }}" 54 | -------------------------------------------------------------------------------- /tasks/section_1/cis_1.1.2.4.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "1.1.2.4.1 | PATCH | Ensure /var is a seperate partition" 4 | when: 5 | - required_mount not in mount_names 6 | - amazon2cis_rule_1_1_2_4_1 7 | tags: 8 | - level2 9 | - automated 10 | - patch 11 | - rule_1.1.2.4.1 12 | - mounts 13 | - NIST800-53R5_CM-7 14 | vars: 15 | warn_control_id: '1.1.2.4.1' 16 | required_mount: '/var' 17 | block: 18 | - name: "1.1.2.4.1 | AUDIT | Ensure /var is a separate partition | Absent" 19 | ansible.builtin.debug: 20 | msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" 21 | 22 | - name: "1.1.2.4.1 | AUDIT | Ensure /var is a separate partition | Warn Count" 23 | ansible.builtin.import_tasks: 24 | file: warning_facts.yml 25 | 26 | - name: | 27 | "1.1.2.4.2 | PATCH | Ensure nodev option set on /var partition 28 | 1.1.2.4.3 | PATCH | Ensure nosuid option set on /var partition 29 | when: 30 | - item.mount == "/var" 31 | - amazon2cis_tmp_svc 32 | - amazon2cis_rule_1_1_2_4_2 or 33 | amazon2cis_rule_1_1_2_4_3 34 | tags: 35 | - level2 36 | - automated 37 | - patch 38 | - rule_1.1.2.4.2 39 | - rule_1.1.2.4.3 40 | - mounts 41 | - NIST800-53R5_AC-3 42 | - NIST800-53R5_MP-2 43 | ansible.posix.mount: 44 | name: /var 45 | src: "{{ item.device }}" 46 | fstype: "{{ item.fstype }}" 47 | state: present 48 | opts: defaults,{% if amazon2cis_rule_1_1_2_4_2 %}nodev,{% endif %}{% if amazon2cis_rule_1_1_2_4_3 %}nosuid{% endif %} 49 | notify: Remount var 50 | with_items: 51 | - "{{ ansible_mounts }}" 52 | loop_control: 53 | label: "{{ item.device }}" 54 | -------------------------------------------------------------------------------- /tasks/section_1/cis_1.1.2.5.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "1.1.2.5.1 | PATCH | Ensure /var/tmp is a seperate partition" 4 | when: 5 | - required_mount not in mount_names 6 | - amazon2cis_rule_1_1_2_5_1 7 | tags: 8 | - level2 9 | - automated 10 | - patch 11 | - rule_1.1.2.5.1 12 | - mounts 13 | - NIST800-53R5_CM-7 14 | vars: 15 | warn_control_id: '1.1.2.5.1' 16 | required_mount: '/var/tmp' 17 | block: 18 | - name: "1.1.2.5.1 | AUDIT | Ensure /var/tmp is a separate partition | Absent" 19 | ansible.builtin.debug: 20 | msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" 21 | 22 | - name: "1.1.2.5.1 | AUDIT | Ensure /var/tmp is a separate partition | Warn Count" 23 | ansible.builtin.import_tasks: 24 | file: warning_facts.yml 25 | 26 | - name: | 27 | "1.1.2.5.2 | PATCH | Ensure nodev option set on /var/tmp partition 28 | 1.1.2.5.3 | PATCH | Ensure nosuid option set on /var/tmp partition 29 | 1.1.2.5.4 | PATCH | Ensure noexec option set on /var/tmp partition" 30 | when: 31 | - item.mount == "/var/tmp" 32 | - amazon2cis_tmp_svc 33 | - amazon2cis_rule_1_1_2_5_2 or 34 | amazon2cis_rule_1_1_2_5_3 or 35 | amazon2cis_rule_1_1_2_5_4 36 | tags: 37 | - level2 38 | - automated 39 | - patch 40 | - rule_1.1.2.5.2 41 | - rule_1.1.2.5.3 42 | - rule_1.1.2.5.4 43 | - mounts 44 | - NIST800-53R5_AC-3 45 | - NIST800-53R5_MP-2 46 | ansible.posix.mount: 47 | name: /var/tmp 48 | src: "{{ item.device }}" 49 | fstype: "{{ item.fstype }}" 50 | state: present 51 | opts: defaults,{% if amazon2cis_rule_1_1_2_5_2 %}nodev,{% endif %}{% if amazon2cis_rule_1_1_2_5_3 %}nosuid,{% endif %}{% if amazon2cis_rule_1_1_2_5_4 %}noexec{% endif %} 52 | notify: Remount var_tmp 53 | with_items: 54 | - "{{ ansible_mounts }}" 55 | loop_control: 56 | label: "{{ item.device }}" 57 | -------------------------------------------------------------------------------- /tasks/section_1/cis_1.1.2.6.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "1.1.2.6.1 | PATCH | Ensure /var/log is a seperate partition" 4 | when: 5 | - required_mount not in mount_names 6 | - amazon2cis_rule_1_1_2_6_1 7 | tags: 8 | - level2 9 | - automated 10 | - patch 11 | - rule_1.1.2.6.1 12 | - mounts 13 | - NIST800-53R5_CM-7 14 | vars: 15 | warn_control_id: '1.1.2.6.1' 16 | required_mount: '/var/log' 17 | 18 | block: 19 | - name: "1.1.2.6.1 | AUDIT | Ensure /var/log is a separate partition | Absent" 20 | ansible.builtin.debug: 21 | msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" 22 | 23 | - name: "1.1.2.6.1 | AUDIT | Ensure /var/log is a separate partition | Warn Count" 24 | ansible.builtin.import_tasks: 25 | file: warning_facts.yml 26 | 27 | - name: | 28 | "1.1.2.6.2 | PATCH | Ensure nodev option set on /var/log partition 29 | 1.1.2.6.3 | PATCH | Ensure nosuid option set on /var/log partition 30 | 1.1.2.6.4 | PATCH | Ensure noexec option set on /var/log partition" 31 | when: 32 | - item.mount == "/var/log" 33 | - amazon2cis_tmp_svc 34 | - amazon2cis_rule_1_1_2_6_2 or 35 | amazon2cis_rule_1_1_2_6_3 or 36 | amazon2cis_rule_1_1_2_6_4 37 | tags: 38 | - level2 39 | - automated 40 | - patch 41 | - rule_1.1.2.6.2 42 | - rule_1.1.2.6.3 43 | - rule_1.1.2.6.4 44 | - mounts 45 | - NIST800-53R5_AC-3 46 | - NIST800-53R5_MP-2 47 | ansible.posix.mount: 48 | name: /var/log 49 | src: "{{ item.device }}" 50 | fstype: "{{ item.fstype }}" 51 | state: present 52 | opts: defaults,{% if amazon2cis_rule_1_1_2_6_2 %}nodev,{% endif %}{% if amazon2cis_rule_1_1_2_6_3 %}nosuid,{% endif %}{% if amazon2cis_rule_1_1_2_6_4 %}noexec{% endif %} 53 | notify: Remount var_log 54 | with_items: 55 | - "{{ ansible_mounts }}" 56 | loop_control: 57 | label: "{{ item.device }}" 58 | -------------------------------------------------------------------------------- /tasks/section_1/cis_1.1.2.7.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "1.1.2.7.1 | PATCH | Ensure /var/log/audit is a seperate partition" 4 | when: 5 | - required_mount not in mount_names 6 | - amazon2cis_rule_1_1_2_7_1 7 | tags: 8 | - level2 9 | - automated 10 | - patch 11 | - rule_1.1.2.7.1 12 | - mounts 13 | - NIST800-53R5_CM-7 14 | vars: 15 | warn_control_id: '1.1.2.7.1' 16 | required_mount: '/var/log/audit' 17 | block: 18 | - name: "1.1.2.7.1 | AUDIT | Ensure /var/log/audit is a separate partition | Absent" 19 | ansible.builtin.debug: 20 | msg: "Warning!! {{ required_mount }} doesn't exist. This is a manual task" 21 | 22 | - name: "1.1.2.7.1 | AUDIT | Ensure /var/log/audit is a separate partition | Warn Count" 23 | ansible.builtin.import_tasks: 24 | file: warning_facts.yml 25 | 26 | - name: | 27 | "1.1.2.7.2 | PATCH | Ensure nodev option set on /var/log/audit partition 28 | 1.1.2.7.3 | PATCH | Ensure nosuid option set on /var/log/audit partition 29 | 1.1.2.7.4 | PATCH | Ensure noexec option set on /var/log/audit partition" 30 | when: 31 | - item.mount == "/var/log/audit" 32 | - amazon2cis_tmp_svc 33 | - amazon2cis_rule_1_1_2_7_2 or 34 | amazon2cis_rule_1_1_2_7_3 or 35 | amazon2cis_rule_1_1_2_7_4 36 | tags: 37 | - level2 38 | - automated 39 | - patch 40 | - rule_1.1.2.7.2 41 | - rule_1.1.2.7.3 42 | - rule_1.1.2.7.4 43 | - mounts 44 | - NIST800-53R5_AC-3 45 | - NIST800-53R5_MP-2 46 | ansible.posix.mount: 47 | name: /var/log/audit 48 | src: "{{ item.device }}" 49 | fstype: "{{ item.fstype }}" 50 | state: present 51 | opts: defaults,{% if amazon2cis_rule_1_1_2_7_2 %}nodev,{% endif %}{% if amazon2cis_rule_1_1_2_7_3 %}nosuid,{% endif %}{% if amazon2cis_rule_1_1_2_7_4 %}noexec{% endif %} 52 | notify: Remount var_log_audit 53 | with_items: 54 | - "{{ ansible_mounts }}" 55 | loop_control: 56 | label: "{{ item.device }}" 57 | -------------------------------------------------------------------------------- /tasks/section_1/cis_1.2.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "1.2.1 | PATCH | Ensure GPG keys are configured" 4 | when: 5 | - amazon2cis_rule_1_2_1 6 | tags: 7 | - level1 8 | - automated 9 | - patch 10 | - rule_1.2.1 11 | - gpg 12 | - NIST800-53R5_SI-2 13 | ansible.builtin.command: gpg --quiet --with-fingerprint /etc/pki/rpm-gpg/RPM-GPG-KEY-amazon-linux-{{ ansible_distribution_major_version }} 14 | changed_when: "'created' in amazon2cis_1_2_1_status.stderr" 15 | register: amazon2cis_1_2_1_status 16 | 17 | - name: "1.2.2 | PATCH | Ensure gpgcheck is globally activated" 18 | when: 19 | - amazon2cis_rule_1_2_2 20 | tags: 21 | - level1 22 | - automated 23 | - patch 24 | - rule_1.2.2 25 | - gpg 26 | - NIST800-53R5_SI-2 27 | block: 28 | - name: "1.2.2 | PATCH | Ensure gpgcheck is globally activated | find repo files" 29 | ansible.builtin.find: 30 | paths: /etc/yum.repos.d 31 | patterns: "*.repo" 32 | register: amazon2_1_2_2_yum_repos 33 | 34 | - name: "1.2.2 | PATCH | Ensure gpgcheck is globally activated | set gpgcheck" 35 | ansible.builtin.replace: 36 | path: "{{ item.path }}" 37 | regexp: ^gpgcheck\s*=\s*0 38 | replace: "gpgcheck=1" 39 | with_items: 40 | - "{{ amazon2_1_2_2_yum_repos.files }}" 41 | loop_control: 42 | label: "{{ item.path }}" 43 | 44 | - name: "1.2.3 | PATCH | Ensure repo_gpgcheck is globally activated" 45 | when: 46 | - amazon2cis_rule_1_2_3 47 | tags: 48 | - level2 49 | - automated 50 | - patch 51 | - rule_1.2.3 52 | - gpg 53 | - NIST800-53R5_SI-2 54 | ansible.builtin.replace: 55 | path: /etc/yum.conf 56 | regexp: ^repo_gpgcheck\s*=\s*0 57 | replace: "repo_gpgcheck=1" 58 | 59 | - name: "1.2.4 | AUDIT | Ensure package manager repositories are configured" 60 | when: 61 | - amazon2cis_rule_1_2_4 62 | tags: 63 | - level1 64 | - automated 65 | - patch 66 | - rule_1.2.4 67 | - NIST800-53R5_SI-2 68 | vars: 69 | warn_control_id: '1.2.4' 70 | block: 71 | - name: "1.2.4 | AUDIT | Ensure package manager repositories are configured | Get repo list" 72 | ansible.builtin.command: yum repolist 73 | changed_when: false 74 | register: amazon2cis_1_2_4_repolist 75 | 76 | - name: "1.2.4 | AUDIT | Ensure package manager repositories are configured | Show repo list" 77 | ansible.builtin.debug: 78 | msg: 79 | - "Please check against site policy repos listed below match expected:" 80 | - "{{ amazon2cis_1_2_4_repolist.stdout_lines }}" 81 | 82 | - name: "1.2.4 | AUDIT | Ensure package manager repositories are configured | Warn Count" 83 | ansible.builtin.import_tasks: 84 | file: warning_facts.yml 85 | 86 | - name: "1.2.5 | PATCH | Ensure updates, patches, and additional security software are installed" 87 | when: 88 | - amazon2cis_rule_1_2_5 89 | tags: 90 | - level1 91 | - automated 92 | - patch 93 | - rule_1.2.5 94 | - NIST800-53R5_SI-2 95 | vars: 96 | ansible_python_interpreter: /bin/python 97 | ansible.builtin.package: 98 | name: "*" 99 | state: latest 100 | -------------------------------------------------------------------------------- /tasks/section_1/cis_1.3.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "1.3.1 | PATCH | Ensure authentication required for single user mode" 4 | when: 5 | - amazon2cis_rule_1_3_1 6 | - ansible_facts['distribution_major_version'] is version('2', '>=') 7 | tags: 8 | - level1 9 | - automated 10 | - patch 11 | - rule_1.3.1 12 | block: 13 | - name: "1.3.1 | PATCH | Ensure authentication required for single user mode | Emergency service" 14 | ansible.builtin.lineinfile: 15 | path: /usr/lib/systemd/system/emergency.service 16 | regexp: '/sbin/sulogin' 17 | line: 'ExecStart=-/bin/sh -c "/sbin/sulogin; /usr/bin/systemctl --fail --no-block default' 18 | 19 | - name: "1.3.1 | PATCH | Ensure authentication required for single user mode | Rescue service" 20 | ansible.builtin.lineinfile: 21 | path: /usr/lib/systemd/system/rescue.service 22 | regexp: '/sbin/sulogin' 23 | line: 'ExecStart=-/bin/sh -c "/sbin/sulogin; /usr/bin/systemctl --fail --no-block default' 24 | -------------------------------------------------------------------------------- /tasks/section_1/cis_1.4.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "1.4.1 | PATCH | Ensure address space layout randomization (ASLR) is enabled" 4 | when: 5 | - amazon2cis_rule_1_4_1 6 | tags: 7 | - level1 8 | - automated 9 | - patch 10 | - rule_1.4.1 11 | - NIST800-53R5_CM-6 12 | ansible.posix.sysctl: 13 | name: kernel.randomize_va_space 14 | value: '2' 15 | state: present 16 | reload: true 17 | sysctl_set: true 18 | ignoreerrors: true 19 | sysctl_file: "{{ kernel_sysctl_file }}" 20 | 21 | - name: "1.4.2 | PATCH | Ensure ptrace_scope is restricted" 22 | when: 23 | - amazon2cis_rule_1_4_2 24 | tags: 25 | - level1 26 | - automated 27 | - patch 28 | - rule_1.4.2 29 | ansible.posix.sysctl: 30 | name: kernel.yama.ptrace_scope 31 | value: '1' 32 | state: present 33 | reload: true 34 | sysctl_set: true 35 | ignoreerrors: true 36 | sysctl_file: "{{ kernel_sysctl_file }}" 37 | 38 | - name: "1.4.3 | PATCH | Ensure core dump backtraces are disabled" 39 | when: 40 | - amazon2cis_rule_1_4_3 41 | tags: 42 | - level1 43 | - automated 44 | - patch 45 | - rule_1.4.3 46 | - coredump 47 | - NIST800-53R5_CM-6b 48 | notify: Systemd_daemon_reload 49 | ansible.builtin.lineinfile: 50 | path: /etc/systemd/coredump.conf 51 | regexp: ^ProcessSizeMax 52 | line: ProcessSizeMax=0 53 | create: true 54 | mode: '0644' 55 | 56 | - name: "1.4.4 | PATCH | Ensure core dump storage is disabled" 57 | when: 58 | - amazon2cis_rule_1_4_4 59 | tags: 60 | - level1 61 | - automated 62 | - patch 63 | - rule_1.4.4 64 | - coredump 65 | notify: Systemd_daemon_reload 66 | ansible.builtin.lineinfile: 67 | path: /etc/systemd/coredump.conf 68 | regexp: ^Storage 69 | line: Storage=none 70 | create: true 71 | mode: '0644' 72 | -------------------------------------------------------------------------------- /tasks/section_1/cis_1.5.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "1.5.1.1 | PATCH | Ensure SELinux is installed" 4 | when: 5 | - not amazon2cis_selinux_disable 6 | - amazon2cis_rule_1_5_1_1 7 | tags: 8 | - level1 9 | - automated 10 | - patch 11 | - rule_1.5.1.1 12 | - selinux 13 | - NIST800-53R5_AC-3 14 | - NIST800-53R5_MP-2 15 | vars: 16 | ansible_python_interpreter: /bin/python 17 | ansible.builtin.package: 18 | name: libselinux 19 | state: present 20 | 21 | - name: "1.5.1.2 | PATCH | Ensure SELinux is not disabled in bootloader configuration" 22 | when: 23 | - not amazon2cis_selinux_disable 24 | - amazon2cis_rule_1_5_1_2 25 | tags: 26 | - level1 27 | - automated 28 | - patch 29 | - rule_1.5.1.2 30 | - selinux 31 | - NIST800-53R5_AC-3 32 | - NIST800-53R5_MP-2 33 | notify: Rebuild_grub 34 | ansible.builtin.replace: 35 | path: /etc/default/grub 36 | regexp: '{{ item }}' 37 | replace: '' 38 | loop: 39 | - selinux=0 40 | - enforcing=0 41 | 42 | - name: | 43 | "1.5.1.3 | PATCH | Ensure SELinux policy is configured 44 | 1.5.1.4 | PATCH | Ensure the SELinux state is enforcing or permissive" 45 | when: 46 | - not amazon2cis_selinux_disable 47 | - amazon2cis_rule_1_5_1_3 48 | - amazon2cis_rule_1_5_1_4 49 | tags: 50 | - level1 51 | - automated 52 | - patch 53 | - rule_1.5.1.3 54 | - rule_1.5.1.4 55 | - selinux 56 | - NIST800-53R5_AC-3 57 | - NIST800-53R5_MP-2 58 | vars: 59 | ansible_python_interpreter: "{{ python2_bin }}" 60 | ansible.posix.selinux: 61 | conf: /etc/selinux/config 62 | policy: "{{ amazon2cis_selinux_pol }}" 63 | state: "{{ amazon2cis_selinux_state }}" 64 | 65 | - name: "1.5.1.5 | PATCH | Ensure the SELinux state is enforcing" 66 | when: 67 | - not amazon2cis_selinux_disable 68 | - not amazon2cis_selinux_state == "permissive" 69 | - amazon2cis_rule_1_5_1_5 70 | tags: 71 | - level2 72 | - automated 73 | - patch 74 | - rule_1.5.1.5 75 | - selinux 76 | - NIST800-53R5_AC-3 77 | - NIST800-53R5_SI-6 78 | vars: 79 | ansible_python_interpreter: "{{ python2_bin }}" 80 | ansible.posix.selinux: 81 | conf: /etc/selinux/config 82 | policy: "{{ amazon2cis_selinux_pol }}" 83 | state: enforcing 84 | 85 | - name: "1.5.1.6 | AUDIT | Ensure no unconfined services exist" 86 | when: 87 | - amazon2cis_rule_1_5_1_6 88 | tags: 89 | - level1 90 | - automated 91 | - audit 92 | - rule_1.5.1.6 93 | - selinux 94 | - NIST800-53R5_AC-3 95 | - NIST800-53R5_MP-2 96 | vars: 97 | warn_control_id: '1.5.1.6' 98 | block: 99 | - name: "1.5.1.6 | AUDIT | Ensure no unconfined services exist | Find the unconfined services" 100 | ansible.builtin.shell: ps -eZ | grep unconfined_service_t 101 | changed_when: false 102 | failed_when: false 103 | register: amazon2cis_1_5_1_6_unconf_services 104 | 105 | - name: "1.5.1.6 | AUDIT | Ensure no unconfined services exist | Message on unconfined services" 106 | ansible.builtin.debug: 107 | msg: "Warning! You have unconfined services: {{ amazon2cis_1_5_1_6_unconf_services.stdout_lines }}" 108 | when: amazon2cis_1_5_1_6_unconf_services.stdout | length > 0 109 | 110 | - name: "1.5.1.6 | AUDIT | Ensure no unconfined services exist | Warn Count" 111 | ansible.builtin.import_tasks: 112 | file: warning_facts.yml 113 | 114 | - name: "1.5.1.7 | PATCH | Ensure the MCS Translation Service (mcstrans) is not installed" 115 | when: 116 | - amazon2cis_rule_1_5_1_7 117 | tags: 118 | - level1 119 | - automated 120 | - patch 121 | - rule_1.5.1.7 122 | - mcstrans 123 | - NIST800-53R5_SI-4 124 | vars: 125 | ansible_python_interpreter: /bin/python 126 | ansible.builtin.package: 127 | name: mcstrans 128 | state: absent 129 | 130 | - name: "1.5.1.8 | PATCH | Ensure SETroubleshoot is not installed" 131 | when: 132 | - amazon2cis_rule_1_5_1_8 133 | tags: 134 | - level1 135 | - automated 136 | - patch 137 | - rule_1.5.1.8 138 | - selinux 139 | - NIST800-53R5_AC-3 140 | - NIST800-53R5_MP-2 141 | vars: 142 | ansible_python_interpreter: /bin/python 143 | ansible.builtin.package: 144 | name: setroubleshoot 145 | state: absent 146 | -------------------------------------------------------------------------------- /tasks/section_1/cis_1.6.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "1.6.1 | PATCH | Ensure message of the day is configured properly" 4 | when: 5 | - amazon2cis_rule_1_6_1 6 | tags: 7 | - level1 8 | - automated 9 | - patch 10 | - rule_1.6.1 11 | - banner 12 | - NIST800-53R5_CM-1 13 | - NIST800-53R5_CM-3 14 | - NIST800-53R5_CM-6 15 | ansible.builtin.template: 16 | src: etc/motd.j2 17 | dest: /etc/motd 18 | owner: root 19 | group: root 20 | mode: '0644' 21 | 22 | - name: "1.6.2 | PATCH | Ensure local login warning banner is configured properly" 23 | when: 24 | - amazon2cis_rule_1_6_2 25 | tags: 26 | - level1 27 | - automated 28 | - patch 29 | - rule_1.6.2 30 | - banner 31 | - NIST800-53R5_CM-1 32 | - NIST800-53R5_CM-3 33 | - NIST800-53R5_CM-6 34 | ansible.builtin.template: 35 | src: etc/issue.j2 36 | dest: /etc/issue 37 | owner: root 38 | group: root 39 | mode: '0644' 40 | 41 | - name: "1.6.3 | PATCH | Ensure remote login warning banner is configured properly" 42 | when: 43 | - amazon2cis_rule_1_6_3 44 | tags: 45 | - level1 46 | - automated 47 | - patch 48 | - rule_1.6.3 49 | - banner 50 | - NIST800-53R5_CM-1 51 | - NIST800-53R5_CM-3 52 | - NIST800-53R5_CM-6 53 | ansible.builtin.template: 54 | src: etc/issue.net.j2 55 | dest: /etc/issue.net 56 | owner: root 57 | group: root 58 | mode: '0644' 59 | 60 | - name: "1.6.4 | PATCH | Ensure permissions on /etc/motd are configured" 61 | when: 62 | - amazon2cis_rule_1_6_4 63 | tags: 64 | - level1 65 | - automated 66 | - patch 67 | - rule_1.6.4 68 | - banner 69 | - permissions 70 | - NIST800-53R5_MP-2 71 | - NIST800-53R5_AC-3 72 | ansible.builtin.file: 73 | path: /etc/motd 74 | state: file 75 | owner: root 76 | group: root 77 | mode: '0644' 78 | 79 | - name: "1.6.5 | PATCH | Ensure permissions on /etc/issue are configured" 80 | when: 81 | - amazon2cis_rule_1_6_5 82 | tags: 83 | - level1 84 | - automated 85 | - patch 86 | - rule_1.6.5 87 | - banner 88 | - permissions 89 | - NIST800-53R5_MP-2 90 | - NIST800-53R5_AC-3 91 | ansible.builtin.file: 92 | path: /etc/issue 93 | state: file 94 | owner: root 95 | group: root 96 | mode: '0644' 97 | 98 | - name: "1.6.6 | PATCH | Ensure permissions on /etc/issue.net are configured" 99 | when: 100 | - amazon2cis_rule_1_6_6 101 | tags: 102 | - level1 103 | - automated 104 | - patch 105 | - rule_1.6.6 106 | - banner 107 | - permissions 108 | - NIST800-53R5_MP-2 109 | - NIST800-53R5_AC-3 110 | ansible.builtin.file: 111 | path: /etc/issue.net 112 | state: file 113 | owner: root 114 | group: root 115 | mode: '0644' 116 | -------------------------------------------------------------------------------- /tasks/section_1/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "SECTION | 1.1.1.x | Configure FileSystem Kernel Modules" 4 | ansible.builtin.import_tasks: 5 | file: cis_1.1.1.x.yml 6 | 7 | - name: "SECTION | 1.1.2.1.x | FileSystem Configuration /tmp" 8 | ansible.builtin.import_tasks: 9 | file: cis_1.1.2.1.x.yml 10 | 11 | - name: "SECTION | 1.1.2.2.x | FileSystem Configuration /dev/shm" 12 | ansible.builtin.import_tasks: 13 | file: cis_1.1.2.2.x.yml 14 | 15 | - name: "SECTION | 1.1.2.3.x | FileSystem Configuration /home" 16 | ansible.builtin.import_tasks: 17 | file: cis_1.1.2.3.x.yml 18 | 19 | - name: "SECTION | 1.1.2.4.x | FileSystem Configuration /var" 20 | ansible.builtin.import_tasks: 21 | file: cis_1.1.2.4.x.yml 22 | 23 | - name: "SECTION | 1.1.2.5.x | FileSystem Configuration /var/tmp" 24 | ansible.builtin.import_tasks: 25 | file: cis_1.1.2.5.x.yml 26 | 27 | - name: "SECTION | 1.1.2.6.x | FileSystem Configuration /var/log" 28 | ansible.builtin.import_tasks: 29 | file: cis_1.1.2.6.x.yml 30 | 31 | - name: "SECTION | 1.1.2.7.x | FileSystem Configuration /var/log/audit" 32 | ansible.builtin.import_tasks: 33 | file: cis_1.1.2.7.x.yml 34 | 35 | - name: "SECTION | 1.2 | Configure Software Updates and Patch Management" 36 | ansible.builtin.import_tasks: 37 | file: cis_1.2.x.yml 38 | 39 | - name: "SECTION | 1.3 | Configure Secure Boot Settings" 40 | ansible.builtin.import_tasks: 41 | file: cis_1.3.x.yml 42 | 43 | - name: "SECTION | 1.4 | Configure Additional Process Hardening" 44 | ansible.builtin.import_tasks: 45 | file: cis_1.4.x.yml 46 | 47 | - name: "SECTION | 1.5 | Mandatory Access Control" 48 | ansible.builtin.import_tasks: 49 | file: cis_1.5.x.yml 50 | when: not amazon2cis_selinux_disable 51 | 52 | - name: "SECTION | 1.6 | Configure Command Line Warning Banners" 53 | ansible.builtin.import_tasks: 54 | file: cis_1.6.x.yml 55 | -------------------------------------------------------------------------------- /tasks/section_2/cis_2.1.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "2.1.1 | PATCH | Ensure time synchronization is in use" 4 | when: 5 | - amazon2cis_rule_2_1_1 6 | tags: 7 | - level1 8 | - automated 9 | - patch 10 | - rule_2.1.1 11 | - ntp 12 | - chrony 13 | - NIST800-53R5_AU-3 14 | - NIST800-53R5_AU-12 15 | block: 16 | - name: "2.1.1 | PATCH | Ensure time synchronization is in use | service install" 17 | ansible.builtin.package: 18 | name: "{{ amazon2cis_time_synchronization }}" 19 | state: present 20 | vars: 21 | ansible_python_interpreter: /bin/python 22 | 23 | - name: "2.1.1 | PATCH | Ensure time synchronization is in use | service start" 24 | ansible.builtin.service: 25 | name: "{{ amazon2cis_time_synchronization }}d" 26 | state: started 27 | enabled: true 28 | 29 | - name: "2.1.1 | PATCH | Ensure time synchronization is in use | service stop ntp" 30 | ansible.builtin.service: 31 | name: ntpd 32 | state: stopped 33 | enabled: false 34 | when: 35 | - "'ntp' in ansible_facts.packages" 36 | - amazon2cis_time_synchronization == "chrony" 37 | 38 | - name: "2.1.1 | PATCH | Ensure time synchronization is in use | service stop chrony" 39 | ansible.builtin.service: 40 | name: chronyds 41 | when: 42 | - "'chrony' in ansible_facts.packages" 43 | - amazon2cis_time_synchronization == "ntp" 44 | 45 | - name: "2.1.2 | PATCH | Ensure chrony is configured | modify /etc/chrony.conf" 46 | when: 47 | - amazon2cis_rule_2_1_2 48 | - amazon2cis_time_synchronization == "chrony" 49 | tags: 50 | - level1 51 | - automated 52 | - patch 53 | - rule_2.1.2 54 | - ntp 55 | - chrony 56 | - NIST800-53R5_AU-3 57 | - NIST800-53R5_AU-12 58 | ansible.builtin.template: 59 | src: chrony.conf.j2 60 | dest: /etc/chrony.conf 61 | owner: root 62 | group: root 63 | mode: '0644' 64 | 65 | - name: "2.1.3 | PATCH | Ensure chrony is configured | modify /etc/sysconfig/chronyd" 66 | when: 67 | - amazon2cis_rule_2_1_3 68 | - amazon2cis_time_synchronization == "chrony" 69 | tags: 70 | - level1 71 | - automated 72 | - patch 73 | - rule_2.1.3 74 | - ntp 75 | - chrony 76 | block: 77 | - name: "2.1.3 | AUDIT | Ensure chrony is configured | Check Setting" 78 | ansible.builtin.shell: grep "u chrony" /etc/sysconfig/chronyd 79 | changed_when: false 80 | failed_when: amazon2_2_1_3_chrony_user.rc not in [ 0, 1 ] 81 | register: amazon2_2_1_3_chrony_user 82 | 83 | - name: "2.1.3 | PATCH | Ensure chrony is configured | modify /etc/sysconfig/chronyd" 84 | when: "'-u chrony' not in amazon2_2_1_3_chrony_user.stdout" 85 | ansible.builtin.lineinfile: 86 | path: /etc/sysconfig/chronyd 87 | regexp: ^OPTIONS=\"(.*)" 88 | line: OPTIONS="\1 -u chrony" 89 | create: true 90 | backrefs: true 91 | mode: '0644' 92 | -------------------------------------------------------------------------------- /tasks/section_2/cis_2.3.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "2.3.1 | PATCH | Ensure ftp client is not installed" 4 | when: 5 | - not amazon2cis_ftp_client 6 | - "'ftp' in ansible_facts.packages" 7 | - amazon2cis_rule_2_3_1 8 | tags: 9 | - level1-server 10 | - level1-workstation 11 | - automated 12 | - patch 13 | - ftp 14 | - NIST800-53R5_CM-7 15 | - rule_2.3.1 16 | ansible.builtin.package: 17 | name: ftp 18 | state: absent 19 | 20 | - name: "2.3.2 | PATCH | Ensure ldap client is not installed" 21 | when: 22 | - not amazon2cis_openldap_clients_required 23 | - "'openldap-clients' in ansible_facts.packages" 24 | - amazon2cis_rule_2_3_2 25 | tags: 26 | - level2-server 27 | - level2-workstation 28 | - automated 29 | - patch 30 | - ldap 31 | - NIST800-53R5_CM-7 32 | - rule_2.3.2 33 | ansible.builtin.package: 34 | name: openldap-clients 35 | state: absent 36 | 37 | - name: "2.3.3 | PATCH | Ensure nis client is not installed" 38 | when: 39 | - not amazon2cis_ypbind_required 40 | - "'ypbind' in ansible_facts.packages" 41 | - amazon2cis_rule_2_3_3 42 | tags: 43 | - level1-server 44 | - level1-workstation 45 | - automated 46 | - patch 47 | - nis 48 | - NIST800-53R5_CM-7 49 | - rule_2.3.3 50 | ansible.builtin.package: 51 | name: ypbind 52 | state: absent 53 | 54 | - name: "2.3.4 | PATCH | Ensure telnet client is not installed" 55 | when: 56 | - not amazon2cis_telnet_required 57 | - "'telnet' in ansible_facts.packages" 58 | - amazon2cis_rule_2_3_4 59 | tags: 60 | - level1-server 61 | - level1-workstation 62 | - automated 63 | - patch 64 | - telnet 65 | - NIST800-53R5_CM-7 66 | - rule_2.3.4 67 | ansible.builtin.package: 68 | name: telnet 69 | state: absent 70 | 71 | - name: "2.3.5 | PATCH | Ensure TFTP client is not installed" 72 | when: 73 | - not amazon2cis_tftp_client 74 | - "'tftp' in ansible_facts.packages" 75 | - amazon2cis_rule_2_3_5 76 | tags: 77 | - level1-server 78 | - level1-workstation 79 | - automated 80 | - patch 81 | - tftp 82 | - NIST800-53R5_CM-7 83 | - rule_2.3.5 84 | ansible.builtin.package: 85 | name: tftp 86 | state: absent 87 | -------------------------------------------------------------------------------- /tasks/section_2/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "SECTION | 2.1.x | Time Synchronization" 4 | ansible.builtin.import_tasks: 5 | file: cis_2.1.x.yml 6 | 7 | - name: "SECTION | 2.1 | Special Purpose Services" 8 | ansible.builtin.import_tasks: 9 | file: cis_2.2.x.yml 10 | 11 | - name: "SECTION | 2.3 | Service Clients" 12 | ansible.builtin.import_tasks: 13 | file: cis_2.3.x.yml 14 | -------------------------------------------------------------------------------- /tasks/section_3/cis_3.1.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "3.1.1 | PATCH | Disable IPv6" 4 | when: 5 | - not amazon2cis_ipv6_required 6 | - amazon2cis_rule_3_1_1 7 | notify: Sysctl_flush_ipv6_routes 8 | tags: 9 | - level2 10 | - manual 11 | - patch 12 | - rule_3.1.1 13 | - ipv6 14 | - NIST800-53R5_CM-7 15 | block: 16 | - name: "3.1.1 | PATCH | Verify if IPv6 is enabled on the system | disable all except localhost" 17 | ansible.posix.sysctl: 18 | name: "{{ item }}" 19 | value: '1' 20 | sysctl_set: true 21 | sysctl_file: "{{ amazon2cis_ipv6_sysctl_file }}" 22 | loop: 23 | - net.ipv6.conf.all.disable_ipv6 24 | - net.ipv6.conf.default.disable_ipv6 25 | 26 | - name: "3.1.1 | PATCH | Verify if IPv6 is enabled on the system | disable localhost sysctl" 27 | when: 28 | - amazon2cis_ipv6_disable_localhost 29 | ansible.posix.sysctl: 30 | name: net.ipv6.conf.lo.disable_ipv6 31 | value: '1' 32 | sysctl_set: true 33 | sysctl_file: "{{ amazon2cis_ipv6_sysctl_file }}" 34 | 35 | - name: "3.1.1 | PATCH | Verify if IPv6 is enabled on the system | disable localhost /etc/hosts" 36 | when: 37 | - amazon2cis_ipv6_disable_localhost 38 | ansible.builtin.lineinfile: 39 | path: /etc/hosts 40 | regexp: '^(::1.*)' 41 | line: '#\1' 42 | backrefs: true 43 | 44 | - name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled" 45 | when: 46 | - amazon2cis_rule_3_1_2 47 | tags: 48 | - level1 49 | - automated 50 | - patch 51 | - rule_3.1.2 52 | - wireless 53 | block: 54 | - name: "3.1.2 | AUDIT | Ensure wireless interfaces are disabled | Check if nmcli command is available" 55 | ansible.builtin.command: rpm -q NetworkManager 56 | changed_when: false 57 | failed_when: false 58 | check_mode: false 59 | register: amazon2_3_1_2_nmcli_available 60 | 61 | - name: "3.1.2 | AUDIT | Ensure wireless interfaces are disabled | Check if wifi is enabled" 62 | ansible.builtin.command: nmcli radio wifi 63 | changed_when: false 64 | failed_when: false 65 | check_mode: false 66 | register: amazon2_3_2_1_wifi_enabled 67 | when: amazon2_3_1_2_nmcli_available.rc == 0 68 | 69 | - name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Disable wifi if enabled" 70 | ansible.builtin.command: nmcli radio wifi off 71 | when: 72 | - amazon2_3_2_1_wifi_enabled.stdout is defined 73 | - "'enabled' in amazon2_3_2_1_wifi_enabled.stdout" 74 | 75 | - name: "3.1.3 | PATCH | Ensure bluetooth services are not in use" 76 | when: 77 | - amazon2cis_rule_3_1_3 78 | tags: 79 | - level1-server 80 | - level2-workstation 81 | - automated 82 | - patch 83 | - sctp 84 | - NIST800-53R5_CM-7 85 | - rule_3.1.3 86 | block: 87 | - name: "3.1.3 | PATCH | Ensure bluetooth services are not in use | pkg" 88 | when: 89 | - not amazon2cis_bluetooth_service 90 | - not amazon2cis_bluetooth_mask 91 | ansible.builtin.package: 92 | name: bluez 93 | state: absent 94 | 95 | - name: "3.1.3 | PATCH | Ensure bluetooth services are not in use | mask" 96 | when: 97 | - not amazon2cis_bluetooth_service 98 | - amazon2cis_bluetooth_mask 99 | notify: Systemd_daemon_reload 100 | ansible.builtin.systemd: 101 | name: bluetooth.service 102 | enabled: false 103 | state: stopped 104 | masked: true 105 | -------------------------------------------------------------------------------- /tasks/section_3/cis_3.2.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "3.2.1 | PATCH | Ensure dccp kernel module is not available" 4 | when: 5 | - amazon2cis_rule_3_2_1 6 | tags: 7 | - level2-server 8 | - level2-workstation 9 | - automated 10 | - dccp 11 | - patch 12 | - NIST800-53R5_CM-7 13 | - NIST800-53R5_SI-4 14 | - rule_3.2.1 15 | block: 16 | - name: "3.2.1 | PATCH | Ensure dccp kernel module is not available | CIS" 17 | ansible.builtin.lineinfile: 18 | path: /etc/modprobe.d/CIS.conf 19 | regexp: "^(#)?install dccp(\\s|$)" 20 | line: "install dccp /bin/true" 21 | create: true 22 | mode: '0600' 23 | 24 | - name: "3.2.1 | PATCH | Ensure dccp kernel module is not available | blacklist" 25 | ansible.builtin.lineinfile: 26 | path: /etc/modprobe.d/blacklist.conf 27 | regexp: "^(#)?blacklist dccp(\\s|$)" 28 | line: "blacklist dccp" 29 | create: true 30 | mode: '0600' 31 | 32 | - name: "3.2.2 | PATCH | Ensure tipc kernel module is not available" 33 | when: 34 | - amazon2cis_rule_3_2_2 35 | tags: 36 | - level2-server 37 | - level2-workstation 38 | - automated 39 | - patch 40 | - tipc 41 | - NIST800-53R5_CM-7 42 | - NIST800-53R5_SI-4 43 | - rule_3.2.2 44 | 45 | block: 46 | - name: "3.2.2 | PATCH | Ensure tipc kernel module is not available | CIS" 47 | ansible.builtin.lineinfile: 48 | path: /etc/modprobe.d/CIS.conf 49 | regexp: "^(#)?install tipc(\\s|$)" 50 | line: "install tipc /bin/true" 51 | create: true 52 | mode: '0600' 53 | 54 | - name: "3.2.2 | PATCH | Ensure tipc kernel module is not available | blacklist" 55 | ansible.builtin.lineinfile: 56 | path: /etc/modprobe.d/blacklist.conf 57 | regexp: "^(#)?blacklist tipc(\\s|$)" 58 | line: "blacklist tipc" 59 | create: true 60 | mode: '0600' 61 | 62 | - name: "3.2.3 | PATCH | Ensure rds kernel module is not available" 63 | when: 64 | - amazon2cis_rule_3_2_3 65 | tags: 66 | - level2-server 67 | - level2-workstation 68 | - automated 69 | - patch 70 | - rds 71 | - NIST800-53R5_CM-7 72 | - NIST800-53R5_SI-4 73 | - rule_3.2.3 74 | block: 75 | - name: "3.2.3 | PATCH | Ensure rds kernel module is not available | CIS" 76 | ansible.builtin.lineinfile: 77 | path: /etc/modprobe.d/CIS.conf 78 | regexp: "^(#)?install rpc(\\s|$)" 79 | line: "install rds /bin/true" 80 | create: true 81 | mode: '0600' 82 | 83 | - name: "3.2.3 | PATCH | Ensure rds kernel module is not available | blacklist" 84 | ansible.builtin.lineinfile: 85 | path: /etc/modprobe.d/blacklist.conf 86 | regexp: "^(#)?blacklist rpc(\\s|$)" 87 | line: "blacklist rds" 88 | create: true 89 | mode: '0600' 90 | 91 | - name: "3.2.4 | PATCH | Ensure sctp kernel module is not available" 92 | when: 93 | - amazon2cis_rule_3_2_4 94 | tags: 95 | - level2-server 96 | - level2-workstation 97 | - automated 98 | - patch 99 | - sctp 100 | - NIST800-53R5_CM-7 101 | - NIST800-53R5_SI-4 102 | - rule_3.2.4 103 | block: 104 | - name: "3.2.4 | PATCH | Ensure sctp kernel module is not available | CIS" 105 | ansible.builtin.lineinfile: 106 | path: /etc/modprobe.d/CIS.conf 107 | regexp: "^(#)?install sctp(\\s|$)" 108 | line: "install sctp /bin/true" 109 | create: true 110 | mode: '0600' 111 | 112 | - name: "3.2.4 | PATCH | Ensure sctp kernel module is not available | blacklist" 113 | ansible.builtin.lineinfile: 114 | path: /etc/modprobe.d/blacklist.conf 115 | regexp: "^(#)?blacklist sctp(\\s|$)" 116 | line: "blacklist sctp" 117 | create: true 118 | mode: '0600' 119 | -------------------------------------------------------------------------------- /tasks/section_3/cis_3.4.1.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "3.4.1.1 | PATCH | Ensure iptables is installed" 4 | when: 5 | - amazon2cis_rule_3_4_1_1 6 | - "'iptables' not in ansible_facts.packages" 7 | tags: 8 | - level1-server 9 | - level1-workstation 10 | - patch 11 | - iptables 12 | - NIST800-53R5_CA-9 13 | - rule_3.4.1.1 14 | ansible.builtin.package: 15 | name: 16 | - iptables 17 | state: present 18 | 19 | - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use" 20 | when: 21 | - amazon2cis_rule_3_4_1_2 22 | tags: 23 | - level1-server 24 | - level1-workstation 25 | - patch 26 | - firewalld 27 | - iptables 28 | - rule_3.4.1.2 29 | block: 30 | - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | firewalld" 31 | when: 32 | - amazon2cis_system_firewall == "firewalld" 33 | - amazon2cis_iptables == "mask" 34 | ansible.builtin.systemd: 35 | name: "{{ item }}" 36 | masked: true 37 | enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" 38 | state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" 39 | loop: 40 | - iptables-services 41 | - ip6tables-services 42 | 43 | - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | firewalld" 44 | when: 45 | - amazon2cis_system_firewall == "firewalld" 46 | - amazon2cis_nftables == "mask" 47 | ansible.builtin.systemd: 48 | name: nftables 49 | masked: true 50 | enabled: "{{ ('nftables' in ansible_facts.packages) | ternary(false, omit) }}" 51 | state: "{{ ('nftables' in ansible_facts.packages) | ternary('stopped', omit) }}" 52 | 53 | - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | iptables" 54 | when: 55 | - amazon2cis_system_firewall == "iptables" 56 | - amazon2cis_nftables == "mask" 57 | ansible.builtin.systemd: 58 | name: nftables 59 | masked: true 60 | enabled: "{{ ('nftables' in ansible_facts.packages) | ternary(false, omit) }}" 61 | state: "{{ ('nftables' in ansible_facts.packages) | ternary('stopped', omit) }}" 62 | 63 | - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | iptables" 64 | when: 65 | - amazon2cis_system_firewall == "iptables" 66 | - amazon2cis_firewalld == "mask" 67 | ansible.builtin.systemd: 68 | name: firewalld 69 | masked: true 70 | enabled: "{{ ('firewalld' in ansible_facts.packages) | ternary(false, omit) }}" 71 | state: "{{ ('firewalld' in ansible_facts.packages) | ternary('stopped', omit) }}" 72 | 73 | - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | nftables" 74 | when: 75 | - amazon2cis_system_firewall == "nftables" 76 | - amazon2cis_iptables == "mask" 77 | ansible.builtin.systemd: 78 | name: "{{ item }}" 79 | masked: true 80 | enabled: "{{ (item in ansible_facts.packages) | ternary(false, omit) }}" 81 | state: "{{ (item in ansible_facts.packages) | ternary('stopped', omit) }}" 82 | loop: 83 | - iptables-services 84 | - ip6tables-services 85 | 86 | - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | nftables" 87 | when: 88 | - amazon2cis_system_firewall == "nftables" 89 | - amazon2cis_firewalld == "mask" 90 | ansible.builtin.systemd: 91 | name: firewalld 92 | masked: true 93 | enabled: "{{ ('firewalld' in ansible_facts.packages) | ternary(false, omit) }}" 94 | state: "{{ ('firewalld' in ansible_facts.packages) | ternary('stopped', omit) }}" 95 | 96 | - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | {{ amazon2cis_system_firewall }} package installed" 97 | when: "amazon2cis_system_firewall not in ansible_facts.packages" 98 | ansible.builtin.package: 99 | name: "{{ amazon2cis_system_firewall }}" 100 | state: present 101 | 102 | - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | {{ amazon2cis_system_firewall }} started and enabled" 103 | ansible.builtin.systemd: 104 | name: "{{ amazon2cis_system_firewall }}" 105 | enabled: true 106 | state: started 107 | 108 | - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | remove nftables" 109 | when: 110 | - amazon2cis_system_firewall != "nftables" 111 | - amazon2cis_nftables == "remove" 112 | ansible.builtin.package: 113 | name: nftables 114 | state: absent 115 | 116 | - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | remove iptables" 117 | when: 118 | - amazon2cis_system_firewall != "iptables" 119 | - amazon2cis_iptables == "remove" 120 | ansible.builtin.package: 121 | name: 122 | - iptables-services 123 | - ip6tables-services 124 | state: absent 125 | 126 | - name: "3.4.1.2 | PATCH | Ensure a single firewall configuration utility is in use | remove firewalld" 127 | when: 128 | - amazon2cis_system_firewall != "firewalld" 129 | - amazon2cis_firewalld == "remove" 130 | ansible.builtin.package: 131 | name: firewalld 132 | state: absent 133 | -------------------------------------------------------------------------------- /tasks/section_3/cis_3.4.2.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "3.4.2.1 | PATCH | Ensure FirewallD is installed" 4 | when: 5 | - amazon2cis_rule_3_4_2_1 6 | tags: 7 | - level1 8 | - automated 9 | - patch 10 | - rule_3.4.2.1 11 | - firewall 12 | - firewalld 13 | - NIST800-53R5_CA-9 14 | ansible.builtin.package: 15 | name: firewalld 16 | state: present 17 | vars: 18 | ansible_python_interpreter: /bin/python 19 | 20 | - name: "3.4.2.2 | PATCH | Ensure firewalld service is enabled and running" 21 | when: 22 | - amazon2cis_rule_3_4_2_2 23 | tags: 24 | - level1 25 | - automated 26 | - patch 27 | - rule_3.4.2.2 28 | - firewall 29 | - firewalld 30 | - NIST800-53R5_CA-9 31 | ansible.builtin.systemd: 32 | name: firewalld 33 | state: started 34 | enabled: true 35 | 36 | - name: "3.4.2.3 | AUDIT | Ensure firewalld drops unnecessary services and ports" 37 | when: 38 | - amazon2cis_rule_3_4_2_3 39 | tags: 40 | - level1 41 | - manual 42 | - audit 43 | - rule_3.4.2.3 44 | - firewall 45 | - NIST800-53R5_CA-9 46 | block: 47 | - name: "3.4.2.3 | AUDIT | Ensure unnecessary services and ports are not accepted | Get list of services and ports" 48 | ansible.builtin.shell: "firewall-cmd --get-active-zones | awk '!/:/ {print $1}' | while read ZN; do firewall-cmd --list-all --zone=$ZN; done" 49 | changed_when: false 50 | failed_when: false 51 | register: amazon2cis_3_4_2_3_services_ports 52 | 53 | - name: "3.4.2.3 | AUDIT | Ensure firewalld drops unnecessary services and ports | Show services and ports" 54 | ansible.builtin.debug: 55 | msg: 56 | - "The items below are the services and ports that are accepted, please correct as needed" 57 | - "{{ amazon2cis_3_4_2_3_services_ports.stdout_lines }}" 58 | 59 | - name: "3.4.2.3 | AUDIT | Ensure firewalld drops unnecessary services and ports | Warn Count" 60 | when: amazon2cis_3_4_2_3_services_ports.stdout | length > 0 61 | vars: 62 | warn_control_id: '3.4.2.3' 63 | ansible.builtin.import_tasks: 64 | file: warning_facts.yml 65 | 66 | - name: "3.4.2.4 | AUDIT | Ensure network interfaces are assigned to appropriate zone" 67 | when: 68 | - amazon2cis_rule_3_4_2_4 69 | tags: 70 | - level1 71 | - manual 72 | - audit 73 | - rule_3.4.2.4 74 | - firewall 75 | - NIST800-53R5_CA-9 76 | block: 77 | - name: "3.4.2.4 | AUDIT | Ensure network interfaces are assigned to appropriate zone | capture output" 78 | ansible.builtin.shell: find /sys/class/net/* -maxdepth 1 | awk -F"/" '{print $NF}' | while read -r netint; do [ "$netint" != "lo" ] && firewall-cmd --get-active-zones | grep -B1 $netint; done 79 | changed_when: false 80 | failed_when: false 81 | register: amazon2cis_3_4_2_4_nics_and_zones 82 | 83 | - name: "3.4.2.4 | AUDIT | Ensure network interfaces are assigned to appropriate zone | Show nics and zones" 84 | ansible.builtin.debug: 85 | msg: 86 | - "The items below are the system network interfaces and associated firewalld zones, please correct as needed" 87 | - "{{ amazon2cis_3_4_2_4_nics_and_zones.stdout_lines }}" 88 | 89 | - name: "3.4.2.4 | AUDIT | Ensure network interfaces are assigned to appropriate zone | Warn Count" 90 | when: amazon2cis_3_4_2_4_nics_and_zones.stdout | length > 0 91 | vars: 92 | warn_control_id: '3.4.2.4' 93 | ansible.builtin.import_tasks: 94 | file: warning_facts.yml 95 | -------------------------------------------------------------------------------- /tasks/section_3/cis_3.4.4.1.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "3.4.4.1.1 | PATCH | Ensure iptables packages are installed" 4 | when: 5 | - amazon2cis_rule_3_4_4_1_1 6 | tags: 7 | - level1 8 | - automated 9 | - patch 10 | - rule_3.4.4.1.1 11 | - firewall 12 | - iptables 13 | - NIST800-53R5_CA-9 14 | vars: 15 | ansible_python_interpreter: /bin/python 16 | ansible.builtin.package: 17 | name: "{{ item }}" 18 | state: present 19 | with_items: 20 | - iptables 21 | - iptables-services 22 | -------------------------------------------------------------------------------- /tasks/section_3/cis_3.4.4.2.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "3.4.4.2.1 | PATCH | Ensure iptables loopback traffic is configured" 4 | when: 5 | - amazon2cis_rule_3_4_4_2_1 6 | tags: 7 | - level1-server 8 | - level1-workstation 9 | - patch 10 | - rule_3.4.4.2.1 11 | - iptables 12 | - NIST800-53R5_CA-9 13 | block: 14 | - name: "3.4.4.2.1 | PATCH | Ensure iptables loopback traffic is configured | INPUT loopback ACCEPT" 15 | ansible.builtin.iptables: 16 | action: append 17 | chain: INPUT 18 | in_interface: lo 19 | jump: ACCEPT 20 | 21 | - name: "3.4.4.2.1 | PATCH | Ensure iptables loopback traffic is configured | OUTPUT loopback ACCEPT" 22 | ansible.builtin.iptables: 23 | action: append 24 | chain: OUTPUT 25 | out_interface: lo 26 | jump: ACCEPT 27 | 28 | - name: "3.4.4.2.1 | PATCH | Ensure iptables loopback traffic is configured | OUTPUT loopback ACCEPT" 29 | ansible.builtin.iptables: 30 | action: append 31 | chain: INPUT 32 | source: 127.0.0.0/8 33 | jump: DROP 34 | 35 | - name: "3.4.4.2.2 | PATCH | Ensure iptables outbound and established connections are configured" 36 | when: 37 | - amazon2cis_rule_3_4_4_2_2 38 | tags: 39 | - level1-server 40 | - level1-workstation 41 | - patch 42 | - rule_3.4.4.2.2 43 | - iptables 44 | - NIST800-53R5_CA-9 45 | ansible.builtin.iptables: 46 | action: append 47 | chain: '{{ item.chain }}' 48 | protocol: '{{ item.protocol }}' 49 | match: state 50 | ctstate: '{{ item.ctstate }}' 51 | jump: ACCEPT 52 | with_items: 53 | - { chain: OUTPUT, protocol: tcp, ctstate: 'NEW,ESTABLISHED' } 54 | - { chain: OUTPUT, protocol: udp, ctstate: 'NEW,ESTABLISHED' } 55 | - { chain: OUTPUT, protocol: icmp, ctstate: 'NEW,ESTABLISHED' } 56 | - { chain: INPUT, protocol: tcp, ctstate: 'ESTABLISHED' } 57 | - { chain: INPUT, protocol: udp, ctstate: 'ESTABLISHED' } 58 | - { chain: INPUT, protocol: icmp, ctstate: 'ESTABLISHED' } 59 | 60 | - name: "3.4.4.2.3 | AUDIT | Ensure iptables firewall rules exist for all open ports" 61 | when: 62 | - amazon2cis_rule_3_4_4_2_3 63 | tags: 64 | - level1-server 65 | - level1-workstation 66 | - audit 67 | - rule_3.4.4.2.3 68 | - iptables 69 | - NIST800-53R5_CA-9 70 | block: 71 | - name: "3.4.4.2.3 | AUDIT | Ensure iptables firewall rules exist for all open ports | Get list of open ports" 72 | ansible.builtin.command: ss -4tuln 73 | changed_when: false 74 | failed_when: false 75 | check_mode: false 76 | register: amazon2cis_3_4_4_2_3_open_ports 77 | 78 | - name: "3.4.4.2.3 | AUDIT | Ensure iptables firewall rules exist for all open ports | Get list of rules" 79 | ansible.builtin.command: iptables -L INPUT -v -n 80 | changed_when: false 81 | failed_when: false 82 | check_mode: false 83 | register: amazon2cis_3_4_4_2_3_current_rules 84 | 85 | - name: "3.4.4.2.3 | AUDIT | Ensure iptables firewall rules exist for all open ports | Alert about settings" 86 | ansible.builtin.debug: 87 | msg: 88 | - "ALERT!!!!Below is the list the open ports and current rules" 89 | - "Please create a rule for any open port that does not have a current rule" 90 | - "Open Ports:" 91 | - "{{ amazon2cis_3_4_4_2_3_open_ports.stdout_lines }}" 92 | - "Current Rules:" 93 | - "{{ amazon2cis_3_4_4_2_3_current_rules.stdout_lines }}" 94 | 95 | - name: "3.4.4.2.3 | WARN | Ensure iptables firewall rules exist for all open ports | Warn Count" 96 | vars: 97 | warn_control_id: '3.4.4.2.3' 98 | ansible.builtin.import_tasks: 99 | file: warning_facts.yml 100 | 101 | - name: "3.4.4.2.4 | PATCH | Ensure iptables default deny firewall policy" 102 | when: 103 | - amazon2cis_rule_3_4_4_2_4 104 | - not system_is_ec2 105 | tags: 106 | - level1-server 107 | - level1-workstation 108 | - patch 109 | - rule_3.4.4.2.4 110 | - iptables 111 | - NIST800-53R5_CA-9 112 | block: 113 | - name: "3.4.4.2.4 | PATCH | Ensure iptables default deny firewall policy | Configure SSH to be allowed in" 114 | ansible.builtin.iptables: 115 | chain: INPUT 116 | protocol: tcp 117 | destination_port: 22 118 | jump: ACCEPT 119 | ctstate: 'NEW,ESTABLISHED' 120 | 121 | - name: "3.4.4.2.4 | PATCH | Ensure iptables default deny firewall policy | Configure SSH to be allowed out" 122 | ansible.builtin.iptables: 123 | chain: OUTPUT 124 | protocol: tcp 125 | source_port: 22 126 | jump: ACCEPT 127 | ctstate: 'NEW,ESTABLISHED' 128 | 129 | - name: "3.4.4.2.4 | PATCH | Ensure iptables default deny firewall policy | Enable apt traffic" 130 | ansible.builtin.iptables: 131 | chain: INPUT 132 | ctstate: 'ESTABLISHED' 133 | jump: ACCEPT 134 | 135 | - name: "3.4.4.2.4 | PATCH | Ensure iptables default deny firewall policy | Set drop items" 136 | ansible.builtin.iptables: 137 | policy: DROP 138 | chain: "{{ item }}" 139 | with_items: 140 | - INPUT 141 | - FORWARD 142 | - OUTPUT 143 | 144 | - name: "3.4.4.2.5 | Ensure iptables rules are saved" 145 | when: 146 | - amazon2cis_save_iptables_cis_rules 147 | - amazon2cis_rule_3_4_4_2_1 or 148 | amazon2cis_rule_3_4_4_2_2 or 149 | amazon2cis_rule_3_4_4_2_3 or 150 | amazon2cis_rule_3_4_4_2_4 or 151 | amazon2cis_rule_3_4_4_2_5 152 | tags: 153 | - level1-server 154 | - level1-workstation 155 | - patch 156 | - rule_3.4.4.2.5 157 | - iptables 158 | - NIST800-53R5_CA-9 159 | block: 160 | - name: "3.4.4.2.5 | Ensure iptables rules are saved " 161 | ansible.builtin.shell: service iptables save 162 | changed_when: amazon2cis_iptables_save.rc == 0 163 | failed_when: amazon2cis_iptables_save.rc != 0 164 | register: amazon2cis_iptables_save 165 | 166 | - name: "3.4.4.2.6 | Ensure iptables service is enabled and running" 167 | when: 168 | - amazon2cis_rule_3_4_4_2_6 169 | tags: 170 | - level1-server 171 | - level1-workstation 172 | - patch 173 | - rule_3.4.4.2.6 174 | - iptables 175 | - NIST800-53R5_CA-9 176 | ansible.builtin.service: 177 | name: iptables 178 | state: started 179 | enabled: true 180 | -------------------------------------------------------------------------------- /tasks/section_3/cis_3.4.4.3.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "3.4.4.3.1 | PATCH | Ensure ip6tables loopback traffic is configured" 4 | when: 5 | - amazon2cis_rule_3_4_4_3_1 6 | tags: 7 | - level1-server 8 | - level1-workstation 9 | - patch 10 | - rule_3.4.4.3.1 11 | - iptables 12 | - ip6tables 13 | - NIST800-53R5_CA-9 14 | block: 15 | - name: "3.4.4.3.1 | PATCH | Ensure ip6tables loopback traffic is configured | INPUT loopback ACCEPT" 16 | ansible.builtin.iptables: 17 | action: append 18 | chain: INPUT 19 | in_interface: lo 20 | jump: ACCEPT 21 | ip_version: ipv6 22 | 23 | - name: "3.4.4.3.1 | PATCH | Ensure ip6tables loopback traffic is configured | OUTPUT loopback ACCEPT" 24 | ansible.builtin.iptables: 25 | action: append 26 | chain: OUTPUT 27 | out_interface: lo 28 | jump: ACCEPT 29 | ip_version: ipv6 30 | 31 | - name: "3.4.4.3.1 | PATCH | Ensure ip6tables loopback traffic is configured | OUTPUT loopback ACCEPT" 32 | ansible.builtin.iptables: 33 | action: append 34 | chain: INPUT 35 | source: ::1 36 | jump: DROP 37 | ip_version: ipv6 38 | 39 | - name: "3.4.4.3.2 | PATCH | Ensure ip6tables outbound and established connections are configured" 40 | when: 41 | - amazon2cis_rule_3_4_4_3_2 42 | tags: 43 | - level1-server 44 | - level1-workstation 45 | - patch 46 | - rule_3.4.4.3.2 47 | - iptables 48 | - ip6tables 49 | - NIST800-53R5_CA-9 50 | ansible.builtin.iptables: 51 | action: append 52 | chain: '{{ item.chain }}' 53 | protocol: '{{ item.protocol }}' 54 | match: state 55 | ctstate: '{{ item.ctstate }}' 56 | jump: ACCEPT 57 | ip_version: ipv6 58 | with_items: 59 | - { chain: OUTPUT, protocol: tcp, ctstate: 'NEW,ESTABLISHED' } 60 | - { chain: OUTPUT, protocol: udp, ctstate: 'NEW,ESTABLISHED' } 61 | - { chain: OUTPUT, protocol: icmp, ctstate: 'NEW,ESTABLISHED' } 62 | - { chain: INPUT, protocol: tcp, ctstate: 'ESTABLISHED' } 63 | - { chain: INPUT, protocol: udp, ctstate: 'ESTABLISHED' } 64 | - { chain: INPUT, protocol: icmp, ctstate: 'ESTABLISHED' } 65 | 66 | - name: "3.4.4.3.3 | AUDIT | Ensure ip6tables firewall rules exist for all open ports" 67 | when: 68 | - amazon2cis_rule_3_4_4_3_3 69 | tags: 70 | - level1-server 71 | - level1-workstation 72 | - audit 73 | - rule_3.4.4.3.3 74 | - iptables 75 | - ip6tables 76 | - NIST800-53R5_CA-9 77 | block: 78 | - name: "3.4.4.3.3 | AUDIT | Ensure ip6tables firewall rules exist for all open ports | Get list of open ports" 79 | ansible.builtin.command: ss -6tuln 80 | changed_when: false 81 | failed_when: false 82 | check_mode: false 83 | register: amazon2cis_3_4_4_3_3_open_ports 84 | 85 | - name: "3.4.4.3.3 | AUDIT | Ensure ip6tables firewall rules exist for all open ports | Get list of rules" 86 | ansible.builtin.command: ip6tables -L INPUT -v -n 87 | changed_when: false 88 | failed_when: false 89 | check_mode: false 90 | register: amazon2cis_3_4_4_3_3_current_rules 91 | 92 | - name: "3.4.4.3.3 | AUDIT | Ensure ip6tables firewall rules exist for all open ports | Alert about settings" 93 | ansible.builtin.debug: 94 | msg: 95 | - "Warning!! Below is the list the open ports and current rules" 96 | - "Please create a rule for any open port that does not have a current rule" 97 | - "Open Ports:" 98 | - "{{ amazon2cis_3_4_4_3_3_open_ports.stdout_lines }}" 99 | - "Current Rules:" 100 | - "{{ amazon2cis_3_4_4_3_3_current_rules.stdout_lines }}" 101 | 102 | - name: "3.4.4.3.3 | WARN | Ensure ip6tables firewall rules exist for all open ports | Warn Count" 103 | vars: 104 | warn_control_id: '3.4.4.3.3' 105 | ansible.builtin.import_tasks: 106 | file: warning_facts.yml 107 | 108 | - name: "3.4.4.3.4 | PATCH | Ensure ip6tables default deny firewall policy" 109 | when: 110 | - amazon2cis_rule_3_4_4_3_4 111 | - not system_is_ec2 112 | tags: 113 | - level1-server 114 | - level1-workstation 115 | - patch 116 | - rule_3.4.4.3.4 117 | - iptables 118 | - ip6tables 119 | - NIST800-53R5_CA-9 120 | block: 121 | - name: "3.4.4.3.4 | PATCH | Ensure ip6tables default deny firewall policy | Configure SSH to be allowed in" 122 | ansible.builtin.iptables: 123 | chain: INPUT 124 | protocol: tcp 125 | destination_port: 22 126 | jump: ACCEPT 127 | ctstate: 'NEW,ESTABLISHED' 128 | ip_version: ipv6 129 | 130 | - name: "3.4.4.3.4 | PATCH | Ensure ip6tables default deny firewall policy | Configure SSH to be allowed out" 131 | ansible.builtin.iptables: 132 | chain: OUTPUT 133 | protocol: tcp 134 | source_port: 22 135 | jump: ACCEPT 136 | ctstate: 'NEW,ESTABLISHED' 137 | ip_version: ipv6 138 | 139 | - name: "3.4.4.3.4 | PATCH | Ensure ip6tables default deny firewall policy | Enable apt traffic" 140 | ansible.builtin.iptables: 141 | chain: INPUT 142 | ctstate: 'ESTABLISHED' 143 | jump: ACCEPT 144 | ip_version: ipv6 145 | 146 | - name: "3.4.4.3.4 | PATCH | Ensure ip6tables default deny firewall policy | Set drop items" 147 | ansible.builtin.iptables: 148 | policy: DROP 149 | chain: "{{ item }}" 150 | ip_version: ipv6 151 | with_items: 152 | - INPUT 153 | - FORWARD 154 | - OUTPUT 155 | 156 | - name: "3.4.4.3.5 | Ensure ip6tables rules are saved" 157 | when: 158 | - amazon2cis_save_ip6tables_cis_rules 159 | - amazon2cis_rule_3_4_4_3_1 or 160 | amazon2cis_rule_3_4_4_3_2 or 161 | amazon2cis_rule_3_4_4_3_3 or 162 | amazon2cis_rule_3_4_4_3_4 or 163 | amazon2cis_rule_3_4_4_3_5 164 | tags: 165 | - level1-server 166 | - level1-workstation 167 | - patch 168 | - rule_3.4.4.3.5 169 | - iptables 170 | - ip6tables 171 | - NIST800-53R5_CA-9 172 | block: 173 | - name: "3.4.4.3.5 | Ensure ip6tables rules are saved " 174 | ansible.builtin.shell: service ip6tables save 175 | changed_when: amazon2cis_ip6tables_save.rc == 0 176 | failed_when: amazon2cis_ip6tables_save.rc != 0 177 | register: amazon2cis_ip6tables_save 178 | 179 | - name: "3.4.4.3.6 | Ensure ip6tables is enabled and running" 180 | when: 181 | - amazon2cis_rule_3_4_4_3_6 182 | tags: 183 | - level1-server 184 | - level1-workstation 185 | - patch 186 | - rule_3.4.4.3.6 187 | - iptables 188 | - ip6tables 189 | - NIST800-53R5_CA-9 190 | ansible.builtin.service: 191 | name: ip6tables 192 | state: started 193 | enabled: true 194 | -------------------------------------------------------------------------------- /tasks/section_3/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "SECTION | 3.1.x | Disable unused network protocols and devices" 4 | ansible.builtin.import_tasks: 5 | file: cis_3.1.x.yml 6 | 7 | - name: "SECTION | 3.2 | Network Kernel modules (Host Only)" 8 | ansible.builtin.import_tasks: 9 | file: cis_3.2.x.yml 10 | 11 | - name: "SECTION | 3.3 | Network Kernel Parameters (Host and Router)" 12 | ansible.builtin.import_tasks: 13 | file: cis_3.3.x.yml 14 | 15 | - name: "SECTION | 3.4.1 | Configure host based firewall" 16 | ansible.builtin.import_tasks: 17 | file: cis_3.4.1.x.yml 18 | 19 | - name: "SECTION | 3.4.2 | Configure firewalld" 20 | when: 21 | - amazon2cis_system_firewall == "firewalld" 22 | ansible.builtin.import_tasks: 23 | file: cis_3.4.2.x.yml 24 | 25 | - name: "SECTION | 3.4.3 | Configure nftables" 26 | when: 27 | - amazon2cis_system_firewall == "nftables" 28 | ansible.builtin.import_tasks: 29 | file: cis_3.4.3.x.yml 30 | 31 | - name: "SECTION | 3.4.4.1.x | Configure iptables software" 32 | when: 33 | - amazon2cis_system_firewall == "iptables" 34 | ansible.builtin.import_tasks: 35 | file: cis_3.4.4.1.x.yml 36 | 37 | - name: "SECTION | 3.4.4.2.x | Configure iptables" 38 | when: 39 | - amazon2cis_system_firewall == "iptables" 40 | ansible.builtin.import_tasks: 41 | file: cis_3.4.4.2.x.yml 42 | 43 | - name: "SECTION | 3.4.4.3.x | Configure ip6tables" 44 | when: 45 | - amazon2cis_system_firewall == "iptables" 46 | - amazon2cis_ipv6_required 47 | ansible.builtin.import_tasks: 48 | file: cis_3.4.4.3.x.yml 49 | -------------------------------------------------------------------------------- /tasks/section_4/cis_4.1.x.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "4.1.1.1 | PATCH | Ensure cron daemon is enabled and active" 4 | when: 5 | - amazon2cis_rule_4_1_1_1 6 | tags: 7 | - level1 8 | - automated 9 | - patch 10 | - rule_4.1.1.1 11 | - cron 12 | - NIST800-53R5_CM-1 13 | - NIST800-53R5_CM-2 14 | - NIST800-53R5_CM-6 15 | - NIST800-53R5_CM-7 16 | - NIST800-53R5_IA-5 17 | ansible.builtin.service: 18 | name: crond 19 | state: started 20 | enabled: true 21 | 22 | - name: "4.1.1.2 | PATCH | Ensure permissions on /etc/crontab are configured" 23 | when: 24 | - amazon2cis_rule_4_1_1_2 25 | tags: 26 | - level1 27 | - automated 28 | - patch 29 | - rule_4.1.1.2 30 | - permissions 31 | - cron 32 | - NIST800-53R5_AC-3 33 | - NIST800-53R5_MP-2 34 | ansible.builtin.file: 35 | dest: /etc/crontab 36 | owner: root 37 | group: root 38 | mode: '0600' 39 | 40 | - name: "4.1.1.3 | PATCH | Ensure permissions on /etc/cron.hourly are configured" 41 | when: 42 | - amazon2cis_rule_4_1_1_3 43 | tags: 44 | - level1 45 | - automated 46 | - patch 47 | - rule_4.1.1.3 48 | - permissions 49 | - cron 50 | - NIST800-53R5_AC-3 51 | - NIST800-53R5_MP-2 52 | ansible.builtin.file: 53 | dest: /etc/cron.hourly 54 | state: directory 55 | owner: root 56 | group: root 57 | mode: '0700' 58 | 59 | - name: "4.1.1.4 | PATCH | Ensure permissions on /etc/cron.daily are configured" 60 | when: 61 | - amazon2cis_rule_4_1_1_4 62 | tags: 63 | - level1 64 | - automated 65 | - patch 66 | - rule_4.1.1.4 67 | - permissions 68 | - cron 69 | - NIST800-53R5_AC-3 70 | - NIST800-53R5_MP-2 71 | ansible.builtin.file: 72 | dest: /etc/cron.daily 73 | state: directory 74 | owner: root 75 | group: root 76 | mode: '0700' 77 | 78 | - name: "4.1.1.5 | PATCH | Ensure permissions on /etc/cron.weekly are configured" 79 | when: 80 | - amazon2cis_rule_4_1_1_5 81 | tags: 82 | - level1 83 | - patch 84 | - rule_4.1.1.5 85 | - permissions 86 | - cron 87 | - NIST800-53R5_AC-3 88 | - NIST800-53R5_MP-2 89 | ansible.builtin.file: 90 | dest: /etc/cron.weekly 91 | state: directory 92 | owner: root 93 | group: root 94 | mode: '0700' 95 | 96 | - name: "4.1.1.6 | PATCH | Ensure permissions on /etc/cron.monthly are configured" 97 | when: 98 | - amazon2cis_rule_4_1_1_6 99 | tags: 100 | - level1 101 | - automated 102 | - patch 103 | - rule_4.1.1.6 104 | - permissions 105 | - cron 106 | - NIST800-53R5_AC-3 107 | - NIST800-53R5_MP-2 108 | ansible.builtin.file: 109 | dest: /etc/cron.monthly 110 | state: directory 111 | owner: root 112 | group: root 113 | mode: '0700' 114 | 115 | - name: "4.1.1.7 | PATCH | Ensure permissions on /etc/cron.d are configured" 116 | when: 117 | - amazon2cis_rule_4_1_1_7 118 | tags: 119 | - level1 120 | - automated 121 | - patch 122 | - rule_4.1.1.7 123 | - permissions 124 | - cron 125 | - NIST800-53R5_AC-3 126 | - NIST800-53R5_MP-2 127 | ansible.builtin.file: 128 | dest: /etc/cron.d 129 | state: directory 130 | owner: root 131 | group: root 132 | mode: '0700' 133 | 134 | - name: "4.1.1.8 | PATCH | Ensure cron is restricted to authorized users" 135 | when: 136 | - amazon2cis_rule_4_1_1_8 137 | tags: 138 | - level1 139 | - automated 140 | - patch 141 | - rule_4.1.1.8 142 | - permissions 143 | - cron 144 | - NIST800-53R5_AC-3 145 | - NIST800-53R5_MP-2 146 | block: 147 | - name: "4.1.1.8 | PATCH | Ensure cron is restricted to authorized users | Remove cron.deny" 148 | ansible.builtin.file: 149 | dest: /etc/cron.deny 150 | state: absent 151 | 152 | - name: "4.1.1.8 | PATCH | Ensure cron is restricted to authorized users | Check if cron.allow exists" 153 | ansible.builtin.stat: 154 | path: "/etc/cron.allow" 155 | register: amazon2cis_4_1_1_8_p 156 | 157 | - name: "4.1.1.8 | PATCH | Ensure cron is restricted to authorized users | Ensure cron.allow is restricted to authorized users" 158 | ansible.builtin.file: 159 | dest: /etc/cron.allow 160 | state: '{{ "file" if amazon2cis_4_1_1_8_p.stat.exists else "touch" }}' 161 | owner: root 162 | group: root 163 | mode: '0600' 164 | 165 | - name: "4.1.2.1 | PATCH | Ensure at is restricted to authorized users" 166 | when: 167 | - amazon2cis_rule_4_1_2_1 168 | tags: 169 | - level1 170 | - automated 171 | - patch 172 | - rule_4.1.2.1 173 | - at 174 | - NIST800-53R5_AC-3 175 | - NIST800-53R5_MP-2 176 | block: 177 | - name: "4.1.2.1 | PATCH | Ensure at is restricted to authorized users | Remove at.deny" 178 | ansible.builtin.file: 179 | dest: /etc/at.deny 180 | state: absent 181 | 182 | - name: "4.1.2.1 | AUDIT | Ensure at is restricted to authorized users | Check if at.allow exists" 183 | ansible.builtin.stat: 184 | path: "/etc/at.allow" 185 | register: amazon2cis_4_1_1_9_p 186 | 187 | - name: "4.1.2.1 | PATCH | Ensure at is restricted to authorized users | Ensure at.allow is restricted to authorized users" 188 | ansible.builtin.file: 189 | dest: /etc/at.allow 190 | state: '{{ "file" if amazon2cis_4_1_1_9_p.stat.exists else "touch" }}' 191 | owner: root 192 | group: root 193 | mode: '0600' 194 | -------------------------------------------------------------------------------- /tasks/section_4/cis_4.3.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "4.3.1 | PATCH | Ensure sudo is installed" 4 | when: 5 | - amazon2cis_rule_4_3_1 6 | tags: 7 | - level1 8 | - automated 9 | - patch 10 | - rule_4.3.1 11 | - sudo 12 | - NIST800-53R5_AC-6 13 | ansible.builtin.package: 14 | name: sudo 15 | state: present 16 | 17 | - name: "4.3.2 | PATCH | Ensure sudo commands use pty" 18 | when: 19 | - amazon2cis_rule_4_3_2 20 | tags: 21 | - level1 22 | - automated 23 | - patch 24 | - rule_4.3.2 25 | - sudo 26 | - NIST800-53R5_AC-6 27 | ansible.builtin.lineinfile: 28 | path: /etc/sudoers 29 | regexp: ^Defaults\s+use_pty 30 | line: "Defaults use_pty" 31 | validate: '/usr/sbin/visudo -cf %s' 32 | 33 | - name: "4.3.3 | PATCH | Ensure sudo log file exists" 34 | when: 35 | - amazon2cis_rule_4_3_3 36 | tags: 37 | - level1 38 | - automated 39 | - patch 40 | - rule_4.3.3 41 | - sudo 42 | - NIST800-53R5_AU-3 43 | - NIST800-53R5_AU-12 44 | ansible.builtin.lineinfile: 45 | path: /etc/sudoers 46 | regexp: '^Defaults\s+logfile=' 47 | line: 'Defaults logfile="{{ amazon2cis_sudolog_location }}"' 48 | validate: '/usr/sbin/visudo -cf %s' 49 | 50 | - name: "4.3.4 | PATCH | Ensure users must provide password for escalation" 51 | when: 52 | - amazon2cis_rule_4_3_4 53 | tags: 54 | - level2-server 55 | - level2-workstation 56 | - automated 57 | - patch 58 | - sudo 59 | - rule_4.3.4 60 | - NIST800-53R5_AC-6 61 | ansible.builtin.replace: 62 | path: "{{ item }}" 63 | regexp: '^([^#|{% if system_is_ec2 %}ec2-user{% endif %}].*)NOPASSWD(.*)' 64 | replace: '\1PASSWD\2' 65 | validate: '/usr/sbin/visudo -cf %s' 66 | loop: "{{ amazon2cis_sudoers_files.stdout_lines }}" 67 | 68 | - name: "4.3.5 | PATCH | Ensure re-authentication for privilege escalation is not disabled globally" 69 | when: 70 | - amazon2cis_rule_4_3_5 71 | tags: 72 | - level1-server 73 | - level1-workstation 74 | - automated 75 | - patch 76 | - sudo 77 | - rule_4.3.5 78 | - NIST800-53R5_AC-6 79 | ansible.builtin.replace: 80 | path: "{{ item }}" 81 | regexp: '^([^#].*)!authenticate(.*)' 82 | replace: '\1authenticate\2' 83 | validate: '/usr/sbin/visudo -cf %s' 84 | loop: "{{ amazon2cis_sudoers_files.stdout_lines }}" 85 | 86 | - name: "4.3.6 | PATCH | Ensure sudo authentication timeout is configured correctly" 87 | when: 88 | - amazon2cis_rule_4_3_6 89 | tags: 90 | - level1-server 91 | - level1-workstation 92 | - automated 93 | - patch 94 | - sudo 95 | - rule_4.3.6 96 | block: 97 | - name: "4.3.6 | AUDIT | Ensure sudo authentication timeout is configured correctly | Get files with timeout set" 98 | ansible.builtin.shell: grep -is 'timestamp_timeout' /etc/sudoers /etc/sudoers.d/* | cut -d":" -f1 | uniq | sort 99 | changed_when: false 100 | failed_when: false 101 | register: amazon2cis_4_3_6_timeout_files 102 | 103 | - name: "4.3.6 | PATCH | Ensure sudo authentication timeout is configured correctly | Set value if no results" 104 | when: amazon2cis_4_3_6_timeout_files.stdout | length == 0 105 | ansible.builtin.lineinfile: 106 | path: /etc/sudoers 107 | regexp: 'Defaults\s+timestamp_timeout=' 108 | line: "Defaults timestamp_timeout={{ amazon2cis_sudo_timestamp_timeout }}" 109 | validate: '/usr/sbin/visudo -cf %s' 110 | 111 | - name: "4.3.6 | PATCH | Ensure sudo authentication timeout is configured correctly | Set value if has results" 112 | when: amazon2cis_4_3_6_timeout_files.stdout | length > 0 113 | ansible.builtin.replace: 114 | path: "{{ item }}" 115 | regexp: 'timestamp_timeout=(\d+)' 116 | replace: "timestamp_timeout={{ amazon2cis_sudo_timestamp_timeout }}" 117 | validate: '/usr/sbin/visudo -cf %s' 118 | loop: "{{ amazon2cis_4_3_6_timeout_files.stdout_lines }}" 119 | 120 | - name: "4.3.7 | PATCH | Ensure access to the su command is restricted" 121 | when: 122 | - amazon2cis_rule_4_3_7 123 | tags: 124 | - level1-server 125 | - level1-workstation 126 | - automated 127 | - patch 128 | - sudo 129 | - rule_4.3.7 130 | - NIST800-53R5_AC-3 131 | - NIST800-53R5_MP-2 132 | block: 133 | - name: "4.3.7 | PATCH | Ensure access to the su command is restricted | Ensure sugroup exists" 134 | ansible.builtin.group: 135 | name: "{{ amazon2cis_sugroup }}" 136 | state: present 137 | register: amazon2cis_4_3_7_sugroup 138 | 139 | - name: "4.3.7 | PATCH | Ensure access to the su command is restricted | remove users from group" 140 | ansible.builtin.lineinfile: 141 | path: /etc/group 142 | regexp: '^{{ amazon2cis_sugroup }}(:.:.*:).*$' 143 | line: '{{ amazon2cis_sugroup }}\g<1>' 144 | backrefs: true 145 | 146 | - name: "4.3.7 | PATCH | Ensure access to the su command is restricted | Setting pam_wheel to use_uid" 147 | ansible.builtin.lineinfile: 148 | path: /etc/pam.d/su 149 | regexp: '^(#)?auth\s+required\s+pam_wheel\.so' 150 | line: 'auth required pam_wheel.so use_uid group={{ amazon2cis_sugroup }}' 151 | -------------------------------------------------------------------------------- /tasks/section_4/cis_4.4.1.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "4.4.1.1 | PATCH | Ensure latest version of pam is installed" 4 | when: 5 | - amazon2cis_rule_4_4_1_1 6 | tags: 7 | - level1-server 8 | - level1-workstation 9 | - automated 10 | - patch 11 | - pam 12 | - rule_4.4.1.1 13 | ansible.builtin.package: 14 | name: pam 15 | state: latest 16 | 17 | - name: "4.4.1.2 | PATCH | Ensure libpwquality is installed" 18 | when: 19 | - amazon2cis_rule_4_4_1_2 20 | tags: 21 | - level1-server 22 | - level1-workstation 23 | - automated 24 | - patch 25 | - pam 26 | - rule_4.4.1.2 27 | - NIST800-53R5_IA-5 28 | ansible.builtin.package: 29 | name: libpwquality 30 | state: present 31 | -------------------------------------------------------------------------------- /tasks/section_4/cis_4.4.2.1.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: | 4 | "4.4.2.1.1 | PATCH | Ensure pam_faillock module is enabled 5 | 4.4.2.1.2 | PATCH | Ensure password failed attempts lockout is configured 6 | 4.4.2.1.3 | PATCH | Ensure password unlock time is configured 7 | 4.4.2.1.4 | PATCH | Ensure password failed attempts lockout includes root account" 8 | when: 9 | - amazon2cis_rule_4_4_2_1_1 or 10 | amazon2cis_rule_4_4_2_1_2 or 11 | amazon2cis_rule_4_4_2_1_3 or 12 | amazon2cis_rule_4_4_2_1_4 13 | tags: 14 | - level1-server 15 | - level1-workstation 16 | - automated 17 | - patch 18 | - pam 19 | - pam_faillock 20 | - rule_4.4.2.1.1 21 | - rule_4.4.2.1.2 22 | - rule_4.4.2.1.3 23 | - rule_4.4.2.1.4 24 | - NIST800-53R5_CM-1 25 | - NIST800-53R5_CM-2 26 | - NIST800-53R5_CM-6 27 | - NIST800-53R5_CM-7 28 | - NIST800-53R5_IA-5 29 | block: 30 | - name: | 31 | "4.4.2.1.1 | PATCH | Ensure pam_faillock module is enabled 32 | 4.4.2.1.2 | PATCH | Ensure password failed attempts lockout is configured 33 | 4.4.2.1.3 | PATCH | Ensure password unlock time is configured 34 | 4.4.2.1.4 | PATCH | Ensure password failed attempts lockout includes root account | auth_required" 35 | community.general.pamd: 36 | name: "{{ item }}" 37 | type: auth 38 | control: required 39 | module_path: pam_env.so 40 | state: after 41 | new_type: auth 42 | new_control: required 43 | new_module_path: pam_faillock.so 44 | module_arguments: 'preauth 45 | silent 46 | audit 47 | {% if amazon2cis_rule_4_4_2_1_2 %}deny="{{ amazon2cis_pam_faillock.deny }}"{% endif %} 48 | {% if amazon2cis_rule_4_4_2_1_3 %}unlock_time="{{ amazon2cis_pam_faillock.unlock_time }}"{% endif %} 49 | {% if amazon2cis_rule_4_4_2_1_4 %}even_deny_root{% endif %}' 50 | loop: 51 | - system-auth 52 | - password-auth 53 | 54 | - name: | 55 | "4.4.2.1.1 | PATCH | Ensure pam_faillock module is enabled 56 | 4.4.2.1.2 | PATCH | Ensure password failed attempts lockout is configured 57 | 4.4.2.1.3 | PATCH | Ensure password unlock time is configured 58 | 4.4.2.1.4 | PATCH | Ensure password failed attempts lockout includes root account | auth_default" 59 | community.general.pamd: 60 | name: "{{ item }}" 61 | type: auth 62 | control: sufficient 63 | module_path: pam_unix.so 64 | state: after 65 | new_type: auth 66 | new_control: '[default=die]' 67 | new_module_path: pam_faillock.so 68 | module_arguments: 'authfail 69 | audit 70 | {% if amazon2cis_rule_4_4_2_1_2 %}deny={{ amazon2cis_pam_faillock.deny }}{% endif %} 71 | {% if amazon2cis_rule_4_4_2_1_3 %}unlock_time={{ amazon2cis_pam_faillock.unlock_time }}{% endif %} 72 | {% if amazon2cis_rule_4_4_2_1_4 %}even_deny_root{% endif %}' 73 | loop: 74 | - system-auth 75 | - password-auth 76 | 77 | - name: | 78 | "4.4.2.1.1 | PATCH | Ensure pam_faillock module is enabled 79 | 4.4.2.1.2 | PATCH | Ensure password failed attempts lockout is configured 80 | 4.4.2.1.3 | PATCH | Ensure password unlock time is configured 81 | 4.4.2.1.4 | PATCH | Ensure password failed attempts lockout includes root account | add to account section" 82 | community.general.pamd: 83 | name: "{{ item }}" 84 | type: account 85 | control: required 86 | module_path: pam_unix.so 87 | state: before 88 | new_type: account 89 | new_control: required 90 | new_module_path: pam_faillock.so 91 | module_arguments: '' 92 | loop: 93 | - system-auth 94 | - password-auth 95 | 96 | - name: "4.4.2.1.2 | PATCH | Ensure password failed attempts lockout is configured" 97 | when: amazon2cis_rule_4_4_2_1_2 98 | tags: 99 | - level1-server 100 | - level1-workstation 101 | - automated 102 | - patch 103 | - pam 104 | - pam_faillock 105 | - rule_4.4.2.1.2 106 | block: 107 | - name: "4.4.2.1.2 | PATCH | Ensure password failed attempts lockout is configured | auth_required" 108 | community.general.pamd: 109 | name: "{{ item }}" 110 | type: auth 111 | control: required 112 | module_path: pam_faillock.so 113 | state: args_present 114 | module_arguments: 'deny={{ amazon2cis_pam_faillock.deny }}' 115 | loop: 116 | - system-auth 117 | - password-auth 118 | 119 | - name: "4.4.2.1.2 | PATCH | Ensure password failed attempts lockout is configured | auth_default" 120 | community.general.pamd: 121 | name: "{{ item }}" 122 | type: auth 123 | control: '[default=die]' 124 | module_path: pam_faillock.so 125 | state: args_present 126 | module_arguments: 'deny={{ amazon2cis_pam_faillock.deny }}' 127 | loop: 128 | - system-auth 129 | - password-auth 130 | 131 | - name: "4.4.2.1.3 | PATCH | Ensure password unlock time is configured" 132 | when: amazon2cis_rule_4_4_2_1_3 133 | tags: 134 | - level1-server 135 | - level1-workstation 136 | - automated 137 | - patch 138 | - pam 139 | - pam_faillock 140 | - rule_4.4.2.1.3 141 | block: 142 | - name: "4.4.2.1.3 | PATCH | Ensure password unlock time is configured | auth_required" 143 | community.general.pamd: 144 | name: "{{ item }}" 145 | type: auth 146 | control: required 147 | module_path: pam_faillock.so 148 | state: args_present 149 | module_arguments: 'unlock_time={{ amazon2cis_pam_faillock.unlock_time }}' 150 | loop: 151 | - system-auth 152 | - password-auth 153 | 154 | - name: "4.4.2.1.3 | PATCH | Ensure password unlock time is configured | auth_default" 155 | community.general.pamd: 156 | name: "{{ item }}" 157 | type: auth 158 | control: '[default=die]' 159 | module_path: pam_faillock.so 160 | state: args_present 161 | module_arguments: 'unlock_time={{ amazon2cis_pam_faillock.unlock_time }}' 162 | loop: 163 | - system-auth 164 | - password-auth 165 | 166 | - name: "4.4.2.1.4 | PATCH | Ensure password failed attempts lockout includes root account" 167 | when: amazon2cis_rule_4_4_2_1_4 168 | tags: 169 | - level1-server 170 | - level1-workstation 171 | - automated 172 | - patch 173 | - pam 174 | - pam_faillock 175 | - rule_4.4.2.1.4 176 | block: 177 | - name: "4.4.2.1.4 | PATCH | Ensure password failed attempts lockout includes root account | auth_required" 178 | community.general.pamd: 179 | name: "{{ item }}" 180 | type: auth 181 | control: required 182 | module_path: pam_faillock.so 183 | state: args_present 184 | module_arguments: 'even_deny_root' 185 | loop: 186 | - system-auth 187 | - password-auth 188 | 189 | - name: "4.4.2.1.4 | PATCH | Ensure password failed attempts lockout includes root account | auth_default" 190 | community.general.pamd: 191 | name: "{{ item }}" 192 | type: auth 193 | control: '[default=die]' 194 | module_path: pam_faillock.so 195 | state: args_present 196 | module_arguments: 'even_deny_root' 197 | loop: 198 | - system-auth 199 | - password-auth 200 | -------------------------------------------------------------------------------- /tasks/section_4/cis_4.4.2.2.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "4.4.2.2.1 | PATCH | Ensure pam_pwquality module is enabled" 4 | when: 5 | - amazon2cis_rule_4_4_2_2_1 6 | tags: 7 | - level1-server 8 | - level1-workstation 9 | - automated 10 | - patch 11 | - pam 12 | - pam_pwquality 13 | - rule_4.4.2.2.1 14 | - NIST800-53R5_IA-5 15 | block: 16 | - name: "4.4.2.2.1 | PATCH | Ensure pam_pwquality module is enabled | present" 17 | community.general.pamd: 18 | name: "{{ item }}" 19 | type: password 20 | control: required 21 | module_path: pam_pwhistory.so 22 | state: before 23 | new_type: password 24 | new_control: requisite 25 | new_module_path: pam_pwquality.so 26 | module_arguments: 'try_first_pass 27 | local_users_only' 28 | loop: 29 | - system-auth 30 | - password-auth 31 | 32 | - name: "4.4.2.2.1 | PATCH | Ensure pam_pwquality module is enabled | args_updated" 33 | community.general.pamd: 34 | name: "{{ item }}" 35 | type: password 36 | control: requisite 37 | module_path: pam_pwquality.so 38 | state: args_present 39 | module_arguments: 'try_first_pass 40 | local_users_only' 41 | loop: 42 | - system-auth 43 | - password-auth 44 | 45 | - name: "4.4.2.2.2 | PATCH | Ensure password number of changed characters is configured" 46 | when: amazon2cis_rule_4_4_2_2_2 47 | tags: 48 | - level1-server 49 | - level1-workstation 50 | - automated 51 | - patch 52 | - pam 53 | - pam_pwquality 54 | - rule_4.4.2.2.2 55 | - NIST800-53R5_IA-5 56 | ansible.builtin.lineinfile: 57 | path: /etc/security/pwquality.conf 58 | regexp: ^(?i)(#|)\s*difok 59 | line: "difok = {{ amazon2cis_pwquality_difok }}" 60 | 61 | - name: "4.4.2.2.3 | PATCH | Ensure password length is configured" 62 | when: amazon2cis_rule_4_4_2_2_3 63 | tags: 64 | - level1-server 65 | - level1-workstation 66 | - automated 67 | - patch 68 | - pam 69 | - pam_pwquality 70 | - rule_4.4.2.2.3 71 | - NIST800-53R5_IA-5 72 | ansible.builtin.lineinfile: 73 | path: /etc/security/pwquality.conf 74 | regexp: ^(?i)(#|)\s*minlen 75 | line: "minlen = {{ amazon2cis_pwquality_minlen }}" 76 | 77 | - name: "4.4.2.2.4 | PATCH | Ensure password complexity is configured" 78 | when: amazon2cis_rule_4_4_2_2_4 79 | tags: 80 | - level1-server 81 | - level1-workstation 82 | - automated 83 | - patch 84 | - pam 85 | - pam_pwquality 86 | - rule_4.4.2.2.4 87 | - NIST800-53R5_IA-5 88 | block: 89 | - name: "4.4.2.2.4 | PATCH | Ensure password complexity is configured | minclass" 90 | ansible.builtin.lineinfile: 91 | path: /etc/security/pwquality.conf 92 | regexp: ^minclass 93 | line: "minclass = {{ amazon2cis_pwquality_minclass_value }}" 94 | when: amazon2cis_pwquality_minclass 95 | 96 | - name: "4.4.2.2.4 | PATCH | Ensure password complexity is configured | seperated values" 97 | ansible.builtin.lineinfile: 98 | path: /etc/security/pwquality.conf 99 | regexp: ^{{ item.key }} 100 | line: "{{ item.key }} = {{ item.value }}" 101 | loop: "{{ amazon2cis_pwquality }}" 102 | when: not amazon2cis_pwquality_minclass 103 | 104 | - name: "4.4.2.2.5 | PATCH | Ensure password same consecutive characters is configured" 105 | when: amazon2cis_rule_4_4_2_2_5 106 | tags: 107 | - level1-server 108 | - level1-workstation 109 | - automated 110 | - patch 111 | - pam 112 | - pam_pwquality 113 | - rule_4.4.2.2.5 114 | - NIST800-53R5_IA-5 115 | ansible.builtin.lineinfile: 116 | path: /etc/security/pwquality.conf 117 | regexp: ^(?i)(#|)\s*maxrepeat 118 | line: "maxrepeat = {{ amazon2cis_pwquality_maxrepeat }}" 119 | 120 | - name: "4.4.2.2.6 | PATCH | Ensure password maximum sequential characters is configured" 121 | when: amazon2cis_rule_4_4_2_2_6 122 | tags: 123 | - level1-server 124 | - level1-workstation 125 | - automated 126 | - patch 127 | - pam 128 | - pam_pwquality 129 | - rule_4.4.2.2.6 130 | - NIST800-53R5_IA-5 131 | ansible.builtin.lineinfile: 132 | path: /etc/security/pwquality.conf 133 | regexp: ^(?i)(#|)\s*maxsequence 134 | line: "maxsequence = {{ amazon2cis_pwquality_maxsequence }}" 135 | 136 | - name: "4.4.2.2.7 | PATCH | Ensure password dictionary check is enabled" 137 | when: amazon2cis_rule_4_4_2_2_7 138 | tags: 139 | - level1-server 140 | - level1-workstation 141 | - automated 142 | - patch 143 | - pam 144 | - pam_pwquality 145 | - rule_4.4.2.2.7 146 | - NIST800-53R5_IA-5 147 | ansible.builtin.lineinfile: 148 | path: /etc/security/pwquality.conf 149 | regexp: ^(?i)(#|)\s*dictcheck 150 | line: "dictcheck = 1" 151 | -------------------------------------------------------------------------------- /tasks/section_4/cis_4.4.2.3.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "4.4.2.3.1 | PATCH | Ensure pam_pwhistory module is enabled" 4 | when: 5 | - amazon2cis_rule_4_4_2_3_1 6 | tags: 7 | - level1-server 8 | - level1-workstation 9 | - automated 10 | - patch 11 | - pam 12 | - pam_pwhistory 13 | - rule_4.4.2.3.1 14 | - NIST800-53R5_IA-5 15 | block: 16 | - name: "4.4.2.3.1 | AUDIT | Ensure pam_pwhistory module is enabled | check if exists" 17 | ansible.builtin.shell: grep -P "^auth\s+(sufficient|required|requisite)\s+pam_pwhistory.so" /etc/pam.d/{system,password}-auth | wc -l 18 | changed_when: false 19 | failed_when: amazon2cis_4_4_2_3_1_pwhistory_exists.rc not in [ 0, 1 ] 20 | register: amazon2cis_4_4_2_3_1_pwhistory_exists 21 | 22 | - name: "4.4.2.3.1 | PATCH | Ensure pam_pwhistory module is enabled | present" 23 | when: amazon2cis_4_4_2_3_1_pwhistory_exists.stdout|int < 2 24 | community.general.pamd: 25 | name: "{{ item }}" 26 | type: password 27 | control: sufficient 28 | module_path: pam_unix.so 29 | state: before 30 | new_type: password 31 | new_control: required 32 | new_module_path: pam_pwhistory.so 33 | module_arguments: 'use_authtok' 34 | loop: 35 | - system-auth 36 | - password-auth 37 | 38 | - name: "4.4.2.3.1 | PATCH | Ensure pam_pwhistory module is enabled | updated" 39 | when: amazon2cis_4_4_2_3_1_pwhistory_exists.stdout | int < 2 40 | community.general.pamd: 41 | name: "{{ item }}" 42 | type: password 43 | control: required 44 | module_path: pam_pwhistory.so 45 | state: args_present 46 | module_arguments: 'use_authtok' 47 | loop: 48 | - system-auth 49 | - password-auth 50 | 51 | - name: "4.4.2.3.2 | PATCH | Ensure password history remember is configured" 52 | when: 53 | - amazon2cis_rule_4_4_2_3_2 54 | tags: 55 | - level1-server 56 | - level1-workstation 57 | - automated 58 | - patch 59 | - pam 60 | - pam_pwhistory 61 | - rule_4.4.2.3.2 62 | - NIST800-53R5_IA-5 63 | community.general.pamd: 64 | name: "{{ item }}" 65 | type: password 66 | control: required 67 | module_path: pam_pwhistory.so 68 | state: args_present 69 | module_arguments: 'remember={{ amazon2cis_pwhistory_remember }}' 70 | loop: 71 | - system-auth 72 | - password-auth 73 | 74 | - name: "4.4.2.3.3 | PATCH | Ensure password history is enforced for the root user" 75 | when: 76 | - amazon2cis_rule_4_4_2_3_3 77 | tags: 78 | - level1-server 79 | - level1-workstation 80 | - automated 81 | - patch 82 | - pam 83 | - pam_pwhistory 84 | - rule_4.4.2.3.3 85 | - NIST800-53R5_IA-5 86 | community.general.pamd: 87 | name: "{{ item }}" 88 | type: password 89 | control: required 90 | module_path: pam_pwhistory.so 91 | state: args_present 92 | module_arguments: 'enforce_for_root' 93 | loop: 94 | - system-auth 95 | - password-auth 96 | 97 | - name: "4.4.2.3.4 | PATCH | Ensure pam_pwhistory includes use_authtok" 98 | when: 99 | - amazon2cis_rule_4_4_2_3_4 100 | tags: 101 | - level1-server 102 | - level1-workstation 103 | - automated 104 | - patch 105 | - pam 106 | - pam_pwhistory 107 | - rule_4.4.2.3.4 108 | - NIST800-53R5_IA-5 109 | community.general.pamd: 110 | name: "{{ item }}" 111 | type: password 112 | control: required 113 | module_path: pam_pwhistory.so 114 | state: args_present 115 | module_arguments: 'use_authtok' 116 | loop: 117 | - system-auth 118 | - password-auth 119 | -------------------------------------------------------------------------------- /tasks/section_4/cis_4.4.2.4.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "4.4.2.4.1 | PATCH | Ensure pam_unix does not include nullok" 4 | when: 5 | - amazon2cis_rule_4_4_2_4_1 6 | tags: 7 | - level1-server 8 | - level1-workstation 9 | - automated 10 | - patch 11 | - pam 12 | - pam_unix 13 | - rule_4.4.2.4.1 14 | - NIST800-53R5_IA-5 15 | ansible.builtin.lineinfile: 16 | backrefs: true 17 | path: "/etc/pam.d/{{ item }}" 18 | regexp: (.*pam_unix.so.*)(nullok)(.*) 19 | line: \1\3 20 | loop: 21 | - system-auth 22 | - password-auth 23 | 24 | - name: "4.4.2.4.2 | PATCH | Ensure pam_unix does not include remember" 25 | when: 26 | - amazon2cis_rule_4_4_2_4_2 27 | tags: 28 | - level1-server 29 | - level1-workstation 30 | - automated 31 | - patch 32 | - pam 33 | - pam_unix 34 | - rule_4.4.2.4.2 35 | ansible.builtin.lineinfile: 36 | backrefs: true 37 | path: "/etc/pam.d/{{ item }}" 38 | regexp: (.*pam_unix.so.*)remember(.*) 39 | line: \1\2 40 | loop: 41 | - system-auth 42 | - password-auth 43 | 44 | - name: "4.4.2.4.3 | PATCH | Ensure pam_unix includes a strong password hashing algorithm" 45 | when: 46 | - amazon2cis_rule_4_4_2_4_3 47 | tags: 48 | - level1-server 49 | - level1-workstation 50 | - automated 51 | - patch 52 | - pam 53 | - pam_unix 54 | - rule_4.4.2.4.3 55 | ansible.builtin.lineinfile: 56 | backrefs: true 57 | path: "/etc/pam.d/{{ item }}" 58 | regexp: (.*pam_unix.so.*)(md5|bigcrypt|sha256|blowfish)(.*) 59 | line: \1\2 sha512 60 | loop: 61 | - system-auth 62 | - password-auth 63 | 64 | - name: "4.4.2.4.4 | PATCH | Ensure pam_unix includes use_authtok" 65 | when: 66 | - amazon2cis_rule_4_4_2_4_4 67 | tags: 68 | - level1-server 69 | - level1-workstation 70 | - automated 71 | - patch 72 | - pam 73 | - pam_unix 74 | - rule_4.4.2.4.4 75 | - NIST800-53R5_IA-5 76 | ansible.builtin.lineinfile: 77 | backrefs: true 78 | path: "/etc/pam.d/{{ item }}" 79 | regexp: (.*pam_unix.so.*)(use_authtok)(.*) 80 | line: \1use_authtok\3 81 | loop: 82 | - system-auth 83 | - password-auth 84 | -------------------------------------------------------------------------------- /tasks/section_4/cis_4.5.2.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "4.5.2.1 | PATCH | Ensure default group for the root account is GID 0" 4 | when: 5 | - amazon2cis_rule_4_5_2_1 6 | tags: 7 | - level1-server 8 | - level1-workstation 9 | - automated 10 | - patch 11 | - NIST800-53R5_CM-1 12 | - NIST800-53R5_CM-2 13 | - NIST800-53R5_CM-6 14 | - NIST800-53R5_CM-7 15 | - NIST800-53R5_IA-5 16 | - root 17 | - rule_4.5.2.1 18 | ansible.builtin.user: 19 | name: root 20 | group: 0 21 | 22 | - name: "4.5.2.2 | PATCH | Ensure root user umask is configured" 23 | when: 24 | - amazon2cis_rule_4_5_2_2 25 | tags: 26 | - level1-server 27 | - level1-workstation 28 | - automated 29 | - patch 30 | - NIST800-53R5_AC-3 31 | - NIST800-53R5_MP-2 32 | - shadow_suite 33 | - rule_4.5.2.2 34 | ansible.builtin.lineinfile: 35 | path: /root/.bash_profile 36 | regexp: \s*umask 37 | line: "umask {{ amazon2cis_root_umask }}" 38 | 39 | - name: "4.5.2.3 | PATCH | Ensure system accounts are secured" 40 | when: 41 | - amazon2cis_rule_4_5_2_3 42 | tags: 43 | - level1-server 44 | - level1-workstation 45 | - automated 46 | - patch 47 | - NIST800-53R5_AC-2 48 | - NIST800-53R5_AC-3 49 | - NIST800-53R5_AC-11 50 | - NIST800-53R5_MP-2 51 | - shadow_suite 52 | - rule_4.5.2.3 53 | block: 54 | - name: "4.5.2.3 | PATCH | | Ensure system accounts are secured | Set nologin" 55 | when: 56 | - item.id != "root" 57 | - item.id != "sync" 58 | - item.id != "shutdown" 59 | - item.id != "halt" 60 | - item.id != "nfsnobody" 61 | - item.uid < amazon2cis_min_uid | int 62 | - item.shell != " /bin/false" 63 | - item.shell != " /usr/sbin/nologin" 64 | ansible.builtin.user: 65 | name: "{{ item.id }}" 66 | shell: /usr/sbin/nologin 67 | loop: "{{ amazon2cis_passwd }}" 68 | loop_control: 69 | label: "{{ item.id }}" 70 | 71 | - name: "4.5.2.3 | PATCH | Ensure system accounts are secured | Lock accounts" 72 | when: 73 | - item.id != "root" 74 | - item.id != "sync" 75 | - item.id != "shutdown" 76 | - item.id != "halt" 77 | - item.id != "nfsnobody" 78 | - item.uid < amazon2cis_min_uid | int 79 | - item.shell != " /bin/false" 80 | - item.shell != " /usr/sbin/nologin" 81 | ansible.builtin.user: 82 | name: "{{ item.id }}" 83 | password_lock: true 84 | loop: "{{ amazon2cis_passwd }}" 85 | loop_control: 86 | label: "{{ item.id }}" 87 | 88 | - name: "4.5.2.4 | PATCH | Ensure root password is set" 89 | when: 90 | - amazon2cis_rule_4_5_2_4 91 | tags: 92 | - level1-server 93 | - level1-workstation 94 | - automated 95 | - patch 96 | - shadow_suite 97 | - rule_4.5.2.4 98 | ansible.builtin.debug: 99 | msg: "This is set as an assert in tasks/main" 100 | -------------------------------------------------------------------------------- /tasks/section_4/cis_4.5.3.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "4.5.3.1 | PATCH | Ensure nologin is not listed in /etc/shells" 4 | when: 5 | - amazon2cis_rule_4_5_3_1 6 | tags: 7 | - level2-server 8 | - level2-workstation 9 | - automated 10 | - NIST800-53R5_CM-1 11 | - NIST800-53R5_CM-2 12 | - NIST800-53R5_CM-6 13 | - NIST800-53R5_CM-7 14 | - NIST800-53R5_IA-5 15 | - patch 16 | - shells 17 | - rule_4.5.3.1 18 | ansible.builtin.replace: 19 | path: /etc/shells 20 | regexp: nologin 21 | replace: "" 22 | 23 | - name: "4.5.3.2 | PATCH | Ensure default user shell timeout is configured" 24 | when: 25 | - amazon2cis_rule_4_5_3_2 26 | tags: 27 | - level1-server 28 | - level1-workstation 29 | - automated 30 | - patch 31 | - NIST800-53R5_AC-3 32 | - NIST800-53R5_MP-2 33 | - shell 34 | - rule_4.5.3.2 35 | ansible.builtin.blockinfile: 36 | path: "{{ item.path }}" 37 | state: "{{ item.state }}" 38 | marker: "# {mark} - CIS benchmark - Ansible-lockdown" 39 | create: true 40 | mode: '0644' 41 | block: | 42 | TMOUT={{ amazon2cis_shell_session_timeout.timeout }} 43 | readonly TMOUT 44 | export TMOUT 45 | loop: 46 | - { path: "{{ amazon2cis_shell_session_timeout.file }}", state: present } 47 | - { path: /etc/profile, state: "{{ (amazon2cis_shell_session_timeout.file == '/etc/profile') | ternary('present', 'absent') }}" } 48 | 49 | - name: "4.5.3.3 | PATCH | Ensure default user umask is configured" 50 | when: 51 | - amazon2cis_rule_4_5_3_3 52 | tags: 53 | - level1-server 54 | - level1-workstation 55 | - automated 56 | - patch 57 | - umask 58 | - NIST800-53R5_AC-3 59 | - NIST800-53R5_MP-2 60 | - rule_4.5.3.3 61 | ansible.builtin.replace: 62 | path: "{{ item.path }}" 63 | regexp: (?i)(umask\s+\d\d\d) 64 | replace: '{{ item.line }} 027' 65 | loop: 66 | - { path: '/etc/bashrc', line: 'umask' } 67 | - { path: '/etc/profile', line: 'umask' } 68 | - { path: '/etc/login.defs', line: 'UMASK' } 69 | -------------------------------------------------------------------------------- /tasks/section_4/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "SECTION | 4.1.x.x | Configure Job Schedulers" 4 | ansible.builtin.import_tasks: 5 | file: cis_4.1.x.x.yml 6 | 7 | - name: "SECTION | 4.2.x | Configure SSH Server" 8 | ansible.builtin.import_tasks: 9 | file: cis_4.2.x.yml 10 | 11 | - name: "SECTION | 4.3.x | Configure Privilege Escalation" 12 | ansible.builtin.import_tasks: 13 | file: cis_4.3.x.yml 14 | 15 | - name: "SECTION | 4.4.1.x | Configure PAM software" 16 | ansible.builtin.import_tasks: 17 | file: cis_4.4.1.x.yml 18 | 19 | - name: "SECTION | 4.4.2.1.x | Configure pam_faillock" 20 | ansible.builtin.import_tasks: 21 | file: cis_4.4.2.1.x.yml 22 | 23 | - name: "SECTION | 4.4.2.2.x | Configure pam_pwquality" 24 | ansible.builtin.import_tasks: 25 | file: cis_4.4.2.2.x.yml 26 | 27 | - name: "SECTION | 4.4.2.3.x | Configure pam_pwhistory" 28 | ansible.builtin.import_tasks: 29 | file: cis_4.4.2.3.x.yml 30 | 31 | - name: "SECTION | 4.4.2.4.x | Configure pam_unix" 32 | ansible.builtin.import_tasks: 33 | file: cis_4.4.2.4.x.yml 34 | 35 | - name: "SECTION | 4.5.1.x | Configure shadow password settings" 36 | ansible.builtin.import_tasks: 37 | file: cis_4.5.1.x.yml 38 | 39 | - name: "SECTION | 4.5.2.x | Configure root and system accounts" 40 | ansible.builtin.import_tasks: 41 | file: cis_4.5.2.x.yml 42 | 43 | - name: "SECTION | 4.5.3.x | Configure user default env" 44 | ansible.builtin.import_tasks: 45 | file: cis_4.5.3.x.yml 46 | -------------------------------------------------------------------------------- /tasks/section_5/cis_5.1.1.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "5.1.1.1 | PATCH | Ensure rsyslog installed" 4 | when: 5 | - "'rsyslog' not in ansible_facts.packages" 6 | - amazon2cis_rule_5_1_1_1 7 | tags: 8 | - level1-server 9 | - level1-workstation 10 | - patch 11 | - rsyslog 12 | - NIST800-53R5_AU-2 13 | - NIST800-53R5_AU-12 14 | - NIST800-53R5_SI-5 15 | - rule_5.1.1.1 16 | ansible.builtin.package: 17 | name: rsyslog 18 | state: present 19 | 20 | - name: "5.1.1.2 | PATCH | Ensure rsyslog service is enabled" 21 | when: 22 | - amazon2cis_rule_5_1_1_2 23 | tags: 24 | - level1-server 25 | - level1-workstation 26 | - patch 27 | - rsyslog 28 | - NIST800-53R5_AU-3 29 | - NIST800-53R5_AU-12 30 | - rule_5.1.1.2 31 | ansible.builtin.systemd: 32 | name: rsyslog 33 | enabled: true 34 | 35 | - name: "5.1.1.3 | PATCH | Ensure journald is configured to send logs to rsyslog" 36 | ansible.builtin.lineinfile: 37 | path: /etc/systemd/journald.conf 38 | regexp: "^#ForwardToSyslog=|^ForwardToSyslog=" 39 | line: ForwardToSyslog=yes 40 | notify: Restart_journald 41 | when: 42 | - amazon2cis_rule_5_1_1_3 43 | - amazon2cis_syslog == "rsyslog" 44 | tags: 45 | - level1-server 46 | - level1-workstation 47 | - patch 48 | - NIST800-53R5_AC-3 49 | - NIST800-53R5_AU-2 50 | - NIST800-53R5_AU-4 51 | - NIST800-53R5_AU-12 52 | - NIST800-53R5_MP-2 53 | - NIST800-53R5_SI-5 54 | - rsyslog 55 | - rule_5.1.1.3 56 | 57 | - name: "5.1.1.4 | PATCH | Ensure rsyslog default file permissions configured" 58 | when: 59 | - amazon2cis_rule_5_1_1_4 60 | tags: 61 | - level1-server 62 | - level1-workstation 63 | - patch 64 | - rsyslog 65 | - rule_5.1.1.4 66 | notify: Restart_rsyslog 67 | ansible.builtin.lineinfile: 68 | path: /etc/rsyslog.conf 69 | regexp: '^\$FileCreateMode' 70 | line: '$FileCreateMode 0640' 71 | 72 | - name: "5.1.1.5 | PATCH | Ensure logging is configured" 73 | when: 74 | - amazon2cis_rule_5_1_1_5 75 | tags: 76 | - level1-server 77 | - level1-workstation 78 | - patch 79 | - rsyslog 80 | - rule_5.1.1.5 81 | notify: Restart_rsyslog 82 | block: 83 | - name: "5.1.1.5 | AUDIT | Ensure logging is configured | rsyslog current config message out" 84 | ansible.builtin.shell: cat /etc/rsyslog.conf 85 | changed_when: false 86 | failed_when: false 87 | check_mode: false 88 | register: amazon2_5_1_1_5_audit 89 | 90 | - name: "5.1.1.5 | AUDIT | Ensure logging is configured | rsyslog current config message out" 91 | ansible.builtin.debug: 92 | msg: 93 | - "These are the current logging configurations for rsyslog, please review:" 94 | - "{{ amazon2_5_1_1_5_audit.stdout_lines }}" 95 | 96 | - name: "5.1.1.5 | PATCH | Ensure logging is configured | mail.* log setting" 97 | when: amazon2cis_rsyslog_ansiblemanaged 98 | ansible.builtin.blockinfile: 99 | path: /etc/rsyslog.conf 100 | marker: "# {mark} MAIL LOG SETTINGS - CIS benchmark - Ansible-lockdown" 101 | block: | 102 | # mail logging additions to meet CIS standards 103 | mail.* -/var/log/mail 104 | mail.info -/var/log/mail.info 105 | mail.warning -/var/log/mail.warning 106 | mail.err /var/log/mail.err 107 | insertafter: '# Log all the mail messages in one place.' 108 | 109 | - name: "5.1.1.5 | PATCH | Ensure logging is configured | Misc. log setting" 110 | when: amazon2cis_rsyslog_ansiblemanaged 111 | ansible.builtin.blockinfile: 112 | path: /etc/rsyslog.conf 113 | state: present 114 | marker: "# {mark} MISC. LOG SETTINGS - CIS benchmark - Ansible-lockdown" 115 | block: | 116 | # misc. logging additions to meet CIS standards 117 | *.=warning;*.=err -/var/log/warn 118 | *.crit /var/log/warn 119 | *.*;mail.none;news.none /var/log/messages 120 | insertafter: '#### RULES ####' 121 | 122 | - name: "5.1.1.5 | PATCH | Ensure logging is configured | Local log settings" 123 | ansible.builtin.blockinfile: 124 | path: /etc/rsyslog.conf 125 | state: present 126 | marker: "#{mark} LOCAL LOG SETTINGS - CIS benchmark - Ansible-lockdown" 127 | block: | 128 | # local log settings to meet CIS standards 129 | local0,local1.* -/var/log/localmessages 130 | local2,local3.* -/var/log/localmessages 131 | local4,local5.* -/var/log/localmessages 132 | local6,local7.* -/var/log/localmessages 133 | *.emerg :omusrmsg:* 134 | insertafter: '#### RULES ####' 135 | 136 | - name: "5.1.1.5 | PATCH | Ensure logging is configured | Auth Settings" 137 | ansible.builtin.blockinfile: 138 | path: /etc/rsyslog.conf 139 | state: present 140 | marker: "#{mark} Auth SETTINGS - CIS benchmark - Ansible-lockdown" 141 | block: | 142 | # Private settings to meet CIS standards 143 | auth,authpriv.* /var/log/secure 144 | insertafter: '#### RULES ####' 145 | 146 | - name: "5.1.1.5 | PATCH | Ensure logging is configured | Cron Settings" 147 | ansible.builtin.blockinfile: 148 | path: /etc/rsyslog.conf 149 | state: present 150 | marker: "#{mark} Cron SETTINGS - CIS benchmark - Ansible-lockdown" 151 | block: | 152 | # Cron settings to meet CIS standards 153 | cron.* /var/log/cron 154 | insertafter: '#### RULES ####' 155 | 156 | - name: "5.1.1.6 | PATCH | Ensure rsyslog is configured to send logs to a remote log host" 157 | when: 158 | - amazon2cis_rule_5_1_1_6 159 | - amazon2cis_remote_log_server 160 | tags: 161 | - level1-server 162 | - level1-workstation 163 | - patch 164 | - rsyslog 165 | - rule_5.1.1.6 166 | notify: Restart_rsyslog 167 | ansible.builtin.blockinfile: 168 | path: /etc/rsyslog.conf 169 | state: present 170 | block: | 171 | # target can be IP or FQDN 172 | *.* action(type="omfwd" target="{{ amazon2cis_remote_log_host }}" port="{{ amazon2cis_remote_log_port }}" protocol="{{ amazon2cis_remote_log_protocol }}" action.resumeRetryCount="{{ amazon2cis_remote_log_retrycount }}" queue.type="LinkedList" queue.size="{{ amazon2cis_remote_log_queuesize }}") 173 | insertafter: EOF 174 | register: result 175 | failed_when: 176 | - result is failed 177 | - result.rc != 257 178 | 179 | - name: "5.1.1.7 | PATCH | Ensure rsyslog is not configured to recieve logs from a remote client" 180 | when: 181 | - amazon2cis_rule_5_1_1_7 182 | tags: 183 | - level1-server 184 | - level1-workstation 185 | - patch 186 | - rsyslog 187 | - rule_5.1.1.7 188 | notify: Restart_rsyslog 189 | block: 190 | - name: "5.1.1.7 | PATCH | Ensure rsyslog is not configured to recieve logs from a remote client. | When not log host" 191 | when: not amazon2cis_system_is_log_server 192 | ansible.builtin.replace: 193 | path: /etc/rsyslog.conf 194 | regexp: '{{ item }}' 195 | replace: '#\1' 196 | loop: 197 | - '^(\$ModLoad imtcp)' 198 | - '^(\$InputTCPServerRun)' 199 | - '^(module\(load="imtcp"\))' 200 | - '^(input\(type="imtcp")' 201 | 202 | - name: "5.1.1.7 | PATCH | Ensure rsyslog is not configured to recieve logs from a remote clients. | When log host" 203 | when: amazon2cis_system_is_log_server 204 | ansible.builtin.replace: 205 | path: /etc/rsyslog.conf 206 | regexp: '^#(.*{{ item }}.*)' 207 | replace: '\1' 208 | loop: 209 | - 'ModLoad imtcp' 210 | - 'InputTCPServerRun' 211 | -------------------------------------------------------------------------------- /tasks/section_5/cis_5.1.2.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "5.1.2.1.1 | PATCH | Ensure systemd-journal-remote is installed" 4 | when: 5 | - amazon2cis_rule_5_1_2_1_1 6 | - amazon2cis_syslog == 'journald' 7 | tags: 8 | - level1-server 9 | - level1-workstation 10 | - manual 11 | - patch 12 | - NIST800-53R5_AU-2 13 | - NIST800-53R5_AU-12 14 | - NIST800-53R5_SI-5 15 | - journald 16 | - rule_5.1.2.1.1 17 | ansible.builtin.package: 18 | name: systemd-journal-remote 19 | state: present 20 | 21 | - name: "5.1.2.1.2 | PATCH | Ensure systemd-journal-remote is configured" 22 | when: 23 | - amazon2cis_rule_5_1_2_1_2 24 | - amazon2cis_syslog == 'journald' 25 | tags: 26 | - level1-server 27 | - level1-workstation 28 | - manual 29 | - patch 30 | - NIST800-53R5_AU-2 31 | - NIST800-53R5_AU-12 32 | - NIST800-53R5_SI-5 33 | - journald 34 | - rule_5.1.2.1.2 35 | notify: Restart_systemd_journal_upload 36 | ansible.builtin.lineinfile: 37 | path: /etc/systemd/journal-upload.conf 38 | regexp: "{{ item.regexp }}" 39 | line: "{{ item.line }}" 40 | loop: 41 | - { regexp: 'URL=', line: 'URL={{ amazon2cis_journal_upload_url }}'} 42 | - { regexp: 'ServerKeyFile=', line: 'ServerKeyFile={{ amazon2cis_journal_upload_serverkeyfile }}'} 43 | - { regexp: 'ServerCertificateFile=', line: 'ServerCertificateFile={{ amazon2cis_journal_servercertificatefile }}'} 44 | - { regexp: 'TrustedCertificateFile=', line: 'TrustedCertificateFile={{ amazon2cis_journal_trustedcertificatefile }}'} 45 | 46 | - name: "5.1.2.1.3 | PATCH | Ensure systemd-journal-remote is enabled" 47 | when: 48 | - amazon2cis_system_is_log_server 49 | - amazon2cis_rule_5_1_2_1_3 50 | - amazon2cis_syslog == 'journald' 51 | tags: 52 | - level1-server 53 | - level1-workstation 54 | - automated 55 | - patch 56 | - NIST800-53R5_AU-2 57 | - NIST800-53R5_AU-12 58 | - NIST800-53R5_SI-5 59 | - journald 60 | - rule_5.1.2.1.3 61 | ansible.builtin.systemd: 62 | name: systemd-journal-upload 63 | state: started 64 | enabled: true 65 | 66 | - name: "5.1.2.1.4 | PATCH | Ensure journald is not configured to recieve logs from a remote client" 67 | when: 68 | - not amazon2cis_system_is_log_server 69 | - amazon2cis_rule_5_1_2_1_4 70 | - amazon2cis_syslog == 'journald' 71 | tags: 72 | - level1-server 73 | - level1-workstation 74 | - automated 75 | - patch 76 | - journald 77 | - rule_5.1.2.1.4 78 | ansible.builtin.systemd: 79 | name: systemd-journal-remote.socket 80 | state: stopped 81 | enabled: false 82 | masked: true 83 | 84 | - name: "5.1.2.2 | PATCH | Ensure journald service is enabled" 85 | when: 86 | - amazon2cis_rule_5_1_2_2 87 | - amazon2cis_syslog == 'journald' 88 | tags: 89 | - level1-server 90 | - level1-workstation 91 | - automated 92 | - audit 93 | - journald 94 | - rule_5.1.2.2 95 | block: 96 | - name: "5.1.2.2 | PATCH | Ensure journald service is enabled | Enable service" 97 | ansible.builtin.systemd: 98 | name: systemd-journald 99 | state: started 100 | enabled: true 101 | 102 | - name: "5.1.2.2 | AUDIT | Ensure journald service is enabled | Capture status" 103 | ansible.builtin.shell: systemctl is-enabled systemd-journald.service 104 | changed_when: false 105 | failed_when: false 106 | register: amazon2cis_5_1_2_2_status 107 | 108 | - name: "5.1.2.2 | AUDIT | Ensure journald service is enabled | Alert on bad status" 109 | ansible.builtin.debug: 110 | msg: 111 | - "Warning!! The status of systemd-journald should be static and it is not. Please investigate" 112 | when: "'static' not in amazon2cis_5_1_2_2_status.stdout" 113 | 114 | - name: "5.1.2.2 | AUDIT | Ensure journald service is enabled | Warn Count" 115 | ansible.builtin.import_tasks: 116 | file: warning_facts.yml 117 | vars: 118 | warn_control_id: '5.1.2.2' 119 | when: "'static' not in amazon2cis_5_1_2_2_status.stdout" 120 | 121 | - name: "5.1.2.3 | PATCH | Ensure journald is configured to compress large log files" 122 | when: 123 | - amazon2cis_rule_5_1_2_3 124 | tags: 125 | - level1-server 126 | - level1-workstation 127 | - automated 128 | - patch 129 | - journald 130 | - rule_5.1.2.3 131 | notify: Restart_journald 132 | ansible.builtin.lineinfile: 133 | path: /etc/systemd/journald.conf 134 | regexp: 'Compress=' 135 | line: Compress=yes 136 | insertafter: ^#Compress 137 | validate: /usr/bin/bash -n %s 138 | 139 | - name: "5.1.2.4 | PATCH | Ensure journald is configured to write logfiles to persistent disk" 140 | when: 141 | - amazon2cis_rule_5_1_2_4 142 | tags: 143 | - level1-server 144 | - level1-workstation 145 | - automated 146 | - patch 147 | - journald 148 | - rule_5.1.2.4 149 | notify: Restart_journald 150 | ansible.builtin.lineinfile: 151 | path: /etc/systemd/journald.conf 152 | regexp: 'Storage=' 153 | line: Storage=persistent 154 | state: present 155 | insertafter: ^#Storage 156 | validate: /usr/bin/bash -n %s 157 | 158 | # This is counter to control 5.1.1.3?? 159 | - name: "5.1.2.5 | PATCH | Ensure journald is not configured to send logs to rsyslog" 160 | when: 161 | - amazon2cis_rule_5_1_2_5 162 | - amazon2cis_syslog == 'journald' 163 | tags: 164 | - level1-server 165 | - level2-workstation 166 | - manual 167 | - patch 168 | - journald 169 | - rule_5.1.2.5 170 | notify: Restart_journald 171 | ansible.builtin.lineinfile: 172 | path: /etc/systemd/journald.conf 173 | regexp: "^ForwardToSyslog=" 174 | line: "#ForwardToSyslog=yes" 175 | 176 | - name: "5.1.2.6 | PATCH | Ensure journald log rotation is configured per site policy" 177 | when: 178 | - amazon2cis_rule_5_1_2_6 179 | - amazon2cis_syslog == 'journald' 180 | tags: 181 | - level1-server 182 | - level1-workstation 183 | - manual 184 | - patch 185 | - journald 186 | - rule_5.1.2.6 187 | ansible.builtin.lineinfile: 188 | path: /etc/systemd/journald.conf 189 | regexp: "{{ item.regexp }}" 190 | line: "{{ item.line }}" 191 | notify: Restart_journald 192 | loop: 193 | - { regexp: '^#SystemMaxUse=|^SystemMaxUse=', line: 'SystemMaxUse={{ amazon2cis_journald_systemmaxuse }}'} 194 | - { regexp: '^#SystemKeepFree=|^SystemKeepFree=', line: 'SystemKeepFree={{ amazon2cis_journald_systemkeepfree }}' } 195 | - { regexp: '^#RuntimeMaxUse=|^RuntimeMaxUse=', line: 'RuntimeMaxUse={{ amazon2cis_journald_runtimemaxuse }}'} 196 | - { regexp: '^#RuntimeKeepFree=|^RuntimeKeepFree=', line: 'RuntimeKeepFree={{ amazon2cis_journald_runtimekeepfree }}'} 197 | - { regexp: '^#MaxFileSec=|^MaxFileSec=', line: 'MaxFileSec={{ amazon2cis_journald_maxfilesec }}'} 198 | -------------------------------------------------------------------------------- /tasks/section_5/cis_5.1.3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "5.1.3 | PATCH | Ensure logrotate is configured" 4 | when: 5 | - amazon2cis_rule_5_1_3 6 | tags: 7 | - level1-server 8 | - level1-workstation 9 | - manual 10 | - patch 11 | - logrotate 12 | - rule_5.1.3 13 | block: 14 | - name: "5.1.3 | AUDIT | Ensure logrotate is configured | Get logrotate settings" 15 | ansible.builtin.find: 16 | paths: /etc/logrotate.d/ 17 | register: amazon2cis_log_rotate_conf 18 | 19 | - name: "5.1.3 | PATCH | Ensure logrotate is configured | conf files" 20 | ansible.builtin.replace: 21 | path: "{{ item.path }}" 22 | regexp: '^(\s*)(daily|weekly|monthly|yearly)$' 23 | replace: "\\1{{ amazon2cis_logrotate }}" 24 | loop: "{{ amazon2cis_log_rotate_conf.files }}" 25 | 26 | - name: "5.1.3 | PATCH | Ensure logrotate is configured | logrotate.conf" 27 | ansible.builtin.replace: 28 | path: /etc/logrotate.conf 29 | regexp: '^(\s*)(daily|weekly|monthly|yearly)$' 30 | replace: "\\1{{ amazon2cis_logrotate }}" 31 | -------------------------------------------------------------------------------- /tasks/section_5/cis_5.1.4.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "5.1.4 | PATCH | Ensure all logfiles have appropriate access configured" 4 | when: 5 | - amazon2cis_rule_5_1_4 6 | tags: 7 | - level1-server 8 | - level1-workstation 9 | - patch 10 | - NIST800-53R5_AU-2 11 | - NIST800-53R5_AU-12 12 | - logfiles 13 | - rule_5.1.4 14 | block: 15 | - name: "5.1.4 | AUDIT | Ensure all logfiles have appropriate access configured | find files" 16 | ansible.builtin.shell: find /var/log/ -type f -perm /g+wx,o+rwx -exec ls {} \; 17 | changed_when: false 18 | failed_when: false 19 | register: amazon2cis_5_1_4_logfiles 20 | 21 | - name: "5.1.4 | AUDIT | Ensure all logfiles have appropriate access configured | set_fact" 22 | ansible.builtin.set_fact: 23 | amazon2cis_4_2_3_logfiles_flattened: "{{ amazon2cis_5_1_4_logfiles | json_query('stdout_lines[*]') | flatten }}" # noqa: jinja[invalid] 24 | when: 25 | - amazon2cis_5_1_4_logfiles.stdout_lines | length > 0 26 | - amazon2cis_5_1_4_logfiles is defined 27 | 28 | - name: "5.1.4 | PATCH | Ensure all logfiles have appropriate access configured | change permissions" 29 | ansible.builtin.file: 30 | path: "{{ item }}" 31 | mode: '0640' 32 | loop: "{{ amazon2cis_5_1_4_logfiles_flattened }}" 33 | when: 34 | - amazon2cis_5_1_4_logfiles_flattened is defined 35 | - item != "/var/log/btmp" 36 | - item != "/var/log/utmp" 37 | - item != "/var/log/wtmp" 38 | -------------------------------------------------------------------------------- /tasks/section_5/cis_5.2.1.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "5.2.1.1 | PATCH | Ensure audit is installed" 4 | when: 5 | - amazon2cis_rule_5_2_1_1 6 | tags: 7 | - level2-server 8 | - level2-workstation 9 | - automated 10 | - patch 11 | - NIST800-53R5_AU-2 12 | - NIST800-53R5_AU-3 13 | - NIST800-53R5_AU-12 14 | - NIST800-53R5_SI-5 15 | - auditd 16 | - rule_5.2.1.1 17 | block: 18 | - name: "5.2.1.1 | PATCH | Ensure auditd is installed | Install auditd packages" 19 | ansible.builtin.package: 20 | name: audit 21 | state: present 22 | when: '"auditd" not in ansible_facts.packages' 23 | 24 | - name: "5.2.1.1 | PATCH | Ensure auditd is installed | Install auditd-lib packages" 25 | ansible.builtin.package: 26 | name: audit-libs 27 | state: present 28 | when: '"auditd-lib" not in ansible_facts.packages' 29 | 30 | - name: "5.2.1.2 | PATCH | Ensure auditing for processes that start prior to auditd is enabled" 31 | when: 32 | - amazon2cis_rule_5_2_1_2 33 | tags: 34 | - level2-server 35 | - level2-workstation 36 | - automated 37 | - patch 38 | - auditd 39 | - grub 40 | - rule_5.2.1.2 41 | notify: Rebuild_grub 42 | block: 43 | - name: "5.2.1.2 | AUDIT | Ensure auditing for processes that start prior to auditd is enabled | Get GRUB_CMDLINE_LINUX" 44 | ansible.builtin.shell: grep "GRUB_CMDLINE_LINUX_DEFAULT=" /etc/default/grub | cut -f2 -d'"' 45 | changed_when: false 46 | failed_when: false 47 | check_mode: false 48 | register: amazon2cis_5_2_1_2_grub_cmdline_linux 49 | 50 | - name: "5.2.1.2 | PATCH | Ensure auditing for processes that start prior to auditd is enabled | Replace existing setting" 51 | when: "'audit=' in amazon2cis_5_2_1_2_grub_cmdline_linux.stdout" 52 | ansible.builtin.replace: 53 | dest: /etc/default/grub 54 | regexp: 'audit=([0-9]+)' 55 | replace: 'audit=1' 56 | after: '^GRUB_CMDLINE_LINUX_DEFAULT="' 57 | before: '"' 58 | 59 | - name: "5.2.1.2 | PATCH | Ensure auditing for processes that start prior to auditd is enabled | Add audit setting if missing" 60 | when: "'audit=' not in amazon2cis_5_2_1_2_grub_cmdline_linux.stdout" 61 | ansible.builtin.lineinfile: 62 | path: /etc/default/grub 63 | regexp: '^GRUB_CMDLINE_LINUX_DEFAULT=' 64 | line: 'GRUB_CMDLINE_LINUX_DEFAULT="{{ amazon2cis_5_2_1_2_grub_cmdline_linux.stdout }} audit=1"' 65 | 66 | - name: "5.2.1.3 | PATCH | Ensure audit_backlog_limit is sufficient" 67 | when: 68 | - amazon2cis_rule_5_2_1_3 69 | tags: 70 | - level2-server 71 | - level2-workstation 72 | - automated 73 | - patch 74 | - auditd 75 | - NIST800-53R5_AU-2 76 | - NIST800-53R5_AU-12 77 | - NIST800-53R5_SI-5 78 | - grub 79 | - rule_5.2.1.3 80 | notify: Rebuild_grub 81 | block: 82 | - name: "5.2.1.3 | AUDIT | Ensure audit_backlog_limit is sufficient | Get GRUB_CMDLINE_LINUX" 83 | ansible.builtin.shell: grep 'GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub | cut -f2 -d'"' 84 | changed_when: false 85 | failed_when: false 86 | check_mode: false 87 | register: amazon2cis_5_2_1_3_grub_cmdline_linux 88 | 89 | - name: "5.2.1.3 | PATCH | Ensure audit_backlog_limit is sufficient | Replace existing setting" 90 | when: "'audit_backlog_limit=' in amazon2cis_5_2_1_3_grub_cmdline_linux.stdout" 91 | ansible.builtin.replace: 92 | dest: /etc/default/grub 93 | regexp: 'audit_backlog_limit=([0-9]+)' 94 | replace: 'audit_backlog_limit={{ amazon2cis_audit_back_log_limit }}' 95 | after: '^GRUB_CMDLINE_LINUX_DEFAULT="' 96 | before: '"' 97 | 98 | - name: "5.2.1.3 | PATCH | Ensure audit_backlog_limit is sufficient | Add audit_backlog_limit setting if missing" 99 | when: "'audit_backlog_limit=' not in amazon2cis_5_2_1_3_grub_cmdline_linux.stdout" 100 | ansible.builtin.lineinfile: 101 | path: /etc/default/grub 102 | regexp: '^GRUB_CMDLINE_LINUX_DEFAULT=' 103 | line: 'GRUB_CMDLINE_LINUX_DEFAULT="{{ amazon2cis_5_2_1_3_grub_cmdline_linux.stdout }} audit_backlog_limit={{ amazon2cis_audit_back_log_limit }}"' 104 | 105 | - name: "5.2.1.4 | PATCH | Ensure auditd service is enabled" 106 | when: 107 | - amazon2cis_rule_5_2_1_4 108 | tags: 109 | - level2-server 110 | - level2-workstation 111 | - automated 112 | - patch 113 | - NIST800-53R5_AU-2 114 | - NIST800-53R5_AU-12 115 | - NIST800-53R5_SI-5 116 | - auditd 117 | - rule_5.2.1.4 118 | ansible.builtin.service: 119 | name: auditd 120 | state: started 121 | enabled: true 122 | -------------------------------------------------------------------------------- /tasks/section_5/cis_5.2.2.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "5.2.2.1 | PATCH | Ensure audit log storage size is configured" 4 | when: 5 | - amazon2cis_rule_5_2_2_1 6 | tags: 7 | - level2-server 8 | - level2-workstation 9 | - automated 10 | - patch 11 | - NIST800-53R5_AU-8 12 | - auditd 13 | - rule_5.2.2.1 14 | notify: Restart_auditd 15 | ansible.builtin.lineinfile: 16 | path: /etc/audit/auditd.conf 17 | regexp: ^max_log_file(\s|=) 18 | line: "max_log_file = {{ amazon2cis_max_log_file_size }}" 19 | 20 | - name: "5.2.2.2 | PATCH | Ensure audit logs are not automatically deleted" 21 | when: 22 | - amazon2cis_rule_5_2_2_2 23 | tags: 24 | - level2-server 25 | - level2-workstation 26 | - automated 27 | - patch 28 | - NIST800-53R5_AU-8 29 | - auditd 30 | - rule_5.2.2.2 31 | notify: Restart_auditd 32 | ansible.builtin.lineinfile: 33 | path: /etc/audit/auditd.conf 34 | regexp: "^max_log_file_action" 35 | line: "max_log_file_action = {{ amazon2cis_auditd['max_log_file_action'] }}" 36 | 37 | - name: "5.2.2.3 | PATCH | Ensure system is disabled when audit logs are full" 38 | when: 39 | - amazon2cis_rule_5_2_2_3 40 | tags: 41 | - level2-server 42 | - level2-workstation 43 | - automated 44 | - patch 45 | - NIST800-53R5_AU-2 46 | - NIST800-53R5_AU-8 47 | - NIST800-53R5_AU-12 48 | - NIST800-53R5_SI-5 49 | - auditd 50 | - rule_5.2.2.3 51 | ansible.builtin.lineinfile: 52 | path: /etc/audit/auditd.conf 53 | regexp: "{{ item.regexp }}" 54 | line: "{{ item.line }}" 55 | notify: Restart_auditd 56 | loop: 57 | - { regexp: '^disk_full_action', line: 'disk_full_action = {{ amazon2cis_auditd.disk_full_action }}' } 58 | - { regexp: '^disk_error_action', line: 'disk_error_action = {{ amazon2cis_auditd.disk_error_action }}' } 59 | 60 | - name: "5.2.2.4 | PATCH | Ensure system warns when audit logs are low on space" 61 | when: 62 | - amazon2cis_rule_5_2_2_4 63 | tags: 64 | - level2-server 65 | - level2-workstation 66 | - automated 67 | - patch 68 | - NIST800-53R5_AU-2 69 | - NIST800-53R5_AU-8 70 | - NIST800-53R5_AU-12 71 | - NIST800-53R5_SI-5 72 | - auditd 73 | - rule_5.2.2.4 74 | ansible.builtin.lineinfile: 75 | path: /etc/audit/auditd.conf 76 | regexp: "{{ item.regexp }}" 77 | line: "{{ item.line }}" 78 | notify: Restart_auditd 79 | loop: 80 | - { regexp: '^admin_space_left_action', line: 'admin_space_left_action = {{ amazon2cis_auditd.admin_space_left_action }}' } 81 | - { regexp: '^space_left_action', line: 'space_left_action = {{ amazon2cis_auditd.space_left_action }}' } 82 | -------------------------------------------------------------------------------- /tasks/section_5/cis_5.2.4.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "5.2.4.1 | PATCH | Ensure the audit log directory is 0750 or more restrictive" 4 | when: 5 | - amazon2cis_rule_5_2_4_1 6 | tags: 7 | - level2-server 8 | - level2-workstation 9 | - patch 10 | - auditd 11 | - rule_5.2.4.1 12 | block: 13 | - name: "5.2.4.1 | AUDIT | Ensure the audit log directory is 0750 or more restrictive | get current permissions" 14 | ansible.builtin.stat: 15 | path: "{{ audit_discovered_logfile.stdout | dirname }}" 16 | register: auditlog_dir 17 | 18 | - name: "5.2.4.1 | PATCH | Ensure the audit log directory is 0750 or more restrictive | set" 19 | ansible.builtin.file: 20 | path: "{{ audit_discovered_logfile.stdout | dirname }}" 21 | state: directory 22 | mode: g-w,o-rwx 23 | 24 | - name: | 25 | "5.2.4.2 | PATCH | Ensure audit log files are mode 0640 or less permissive" 26 | "5.2.4.3 | PATCH | Ensure only authorized users own audit log files" 27 | "5.2.4.4 | PATCH | Ensure only authorized groups are assigned ownership of audit log files" 28 | when: 29 | - amazon2cis_rule_5_2_4_2 or 30 | amazon2cis_rule_5_2_4_3 or 31 | amazon2cis_rule_5_2_4_4 32 | tags: 33 | - level2-server 34 | - level2-workstation 35 | - patch 36 | - auditd 37 | - rule_5.2.4.2 38 | - rule_5.2.4.3 39 | - rule_5.2.4.4 40 | block: 41 | - name: "5.2.4.2 | AUDIT | Ensure audit log files are mode 0640 or less permissive | stat file" 42 | ansible.builtin.stat: 43 | path: "{{ audit_discovered_logfile.stdout }}" 44 | changed_when: false 45 | register: auditd_logfile 46 | 47 | - name: | 48 | "5.2.4.2 | PATCH | Ensure audit log files are mode 0640 or less permissive" 49 | "5.2.4.3 | PATCH | Ensure only authorized users own audit log files" 50 | "5.2.4.4 | PATCH | Ensure only authorized groups are assigned ownership of audit log files" 51 | ansible.builtin.file: 52 | path: "{{ audit_discovered_logfile.stdout }}" 53 | mode: "{% if auditd_logfile.stat.mode != '0600' %}0640{% endif %}" 54 | owner: root 55 | group: root 56 | 57 | - name: "5.2.4.5 | PATCH | Ensure audit configuration files are 640 or more restrictive" 58 | when: 59 | - amazon2cis_rule_5_2_4_5 60 | tags: 61 | - level2-server 62 | - level2-workstation 63 | - patch 64 | - auditd 65 | - rule_5.2.4.5 66 | ansible.builtin.file: 67 | path: "{{ item.path }}" 68 | mode: g-wx,o-rwx 69 | loop: "{{ auditd_conf_files.files }}" 70 | loop_control: 71 | label: "{{ item.path }}" 72 | 73 | - name: "5.2.4.6 | PATCH | Ensure audit configuration files are owned by root" 74 | when: 75 | - amazon2cis_rule_5_2_4_6 76 | tags: 77 | - level2-server 78 | - level2-workstation 79 | - patch 80 | - auditd 81 | - rule_5.2.4.6 82 | ansible.builtin.file: 83 | path: "{{ item.path }}" 84 | owner: root 85 | loop: "{{ auditd_conf_files.files }}" 86 | loop_control: 87 | label: "{{ item.path }}" 88 | 89 | - name: "5.2.4.7 | PATCH | Ensure audit configuration files belong to group root" 90 | when: 91 | - amazon2cis_rule_5_2_4_7 92 | tags: 93 | - level2-server 94 | - level2-workstation 95 | - patch 96 | - auditd 97 | - rule_5.2.4.7 98 | ansible.builtin.file: 99 | path: "{{ item.path }}" 100 | group: root 101 | loop: "{{ auditd_conf_files.files }}" 102 | loop_control: 103 | label: "{{ item.path }}" 104 | 105 | - name: "5.2.4.8 | PATCH | Ensure audit tools are 755 or more restrictive" 106 | when: 107 | - amazon2cis_rule_5_2_4_8 108 | tags: 109 | - level2-server 110 | - level2-workstation 111 | - patch 112 | - auditd 113 | - rule_5.2.4.8 114 | block: 115 | - name: "5.2.4.8 | AUDIT | Get audit binary file stat | get current mode" 116 | ansible.builtin.stat: 117 | path: "{{ item }}" 118 | register: "audit_bins" 119 | loop: 120 | - /sbin/auditctl 121 | - /sbin/aureport 122 | - /sbin/ausearch 123 | - /sbin/autrace 124 | - /sbin/auditd 125 | - /sbin/augenrules 126 | 127 | - name: "5.2.4.8 | PATCH | Ensure audit tools are 755 or more restrictive | set if required" 128 | ansible.builtin.file: 129 | path: "{{ item.item }}" 130 | mode: g-w,o-w 131 | loop: "{{ audit_bins.results }}" 132 | loop_control: 133 | label: "{{ item.item }}" 134 | 135 | - name: "5.2.4.9 | PATCH | Ensure audit tools are owned by root" 136 | when: 137 | - amazon2cis_rule_5_2_4_9 138 | tags: 139 | - level2-server 140 | - level2-workstation 141 | - patch 142 | - auditd 143 | - rule_5.2.4.9 144 | ansible.builtin.file: 145 | path: "{{ item }}" 146 | owner: root 147 | group: root 148 | loop: 149 | - /sbin/auditctl 150 | - /sbin/aureport 151 | - /sbin/ausearch 152 | - /sbin/autrace 153 | - /sbin/auditd 154 | - /sbin/augenrules 155 | 156 | - name: "5.2.4.10 | PATCH | Ensure audit tools belong to group root" 157 | when: 158 | - amazon2cis_rule_5_2_4_10 159 | tags: 160 | - level2-server 161 | - level2-workstation 162 | - patch 163 | - auditd 164 | - rule_5.2.4.10 165 | ansible.builtin.file: 166 | path: "{{ item }}" 167 | group: root 168 | loop: 169 | - /sbin/auditctl 170 | - /sbin/aureport 171 | - /sbin/ausearch 172 | - /sbin/autrace 173 | - /sbin/auditd 174 | - /sbin/augenrules 175 | -------------------------------------------------------------------------------- /tasks/section_5/cis_5.3.x.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "5.3.1 | PATCH | Ensure AIDE is installed" 4 | when: 5 | - amazon2cis_config_aide 6 | - amazon2cis_rule_5_3_1 7 | tags: 8 | - level1-server 9 | - level1-workstation 10 | - automated 11 | - aide 12 | - NIST800-53R5_AU-2 13 | - patch 14 | - rule_5.3.1 15 | block: 16 | - name: "5.3.1 | PATCH | Ensure AIDE is installed | Install AIDE" 17 | ansible.builtin.package: 18 | name: aide 19 | state: present 20 | 21 | - name: "5.3.1 | PATCH | Ensure AIDE is installed | Configure AIDE" 22 | ansible.builtin.shell: /usr/sbin/aide --init 23 | changed_when: false 24 | failed_when: false 25 | async: 45 26 | poll: 0 27 | args: 28 | creates: /var/lib/aide/aide.db.new.gz 29 | when: not ansible_check_mode 30 | 31 | - name: "5.3.1 | PATCH | Ensure AIDE is installed | copy AIDE DB" 32 | ansible.builtin.copy: 33 | src: /var/lib/aide/aide.db.new.gz 34 | dest: /var/lib/aide/aide.db.gz 35 | remote_src: true 36 | 37 | - name: "5.3.2 | PATCH | Ensure filesystem integrity is regularly checked" 38 | when: 39 | - amazon2cis_rule_5_3_2 40 | - amazon2cis_config_aide 41 | - not system_is_ec2 42 | tags: 43 | - level1-server 44 | - level1-workstation 45 | - automated 46 | - aide 47 | - NIST800-53R5_AU-2 48 | - file_integrity 49 | - patch 50 | - rule_5.3.2 51 | block: 52 | - name: "5.3.2 | PATCH | Ensure filesystem integrity is regularly checked | cron" 53 | when: amazon2cis_aide_scan == "cron" 54 | ansible.builtin.cron: 55 | name: Run AIDE integrity check 56 | cron_file: "{{ amazon2cis_aide_cron['cron_file'] }}" 57 | user: "{{ amazon2cis_aide_cron['cron_user'] }}" 58 | minute: "{{ amazon2cis_aide_cron['aide_minute'] | default('0') }}" 59 | hour: "{{ amazon2cis_aide_cron['aide_hour'] | default('5') }}" 60 | day: "{{ amazon2cis_aide_cron['aide_day'] | default('*') }}" 61 | month: "{{ amazon2cis_aide_cron['aide_month'] | default('*') }}" 62 | weekday: "{{ amazon2cis_aide_cron['aide_weekday'] | default('*') }}" 63 | job: "{{ amazon2cis_aide_cron['aide_job'] }}" 64 | 65 | - name: "5.3.2 | PATCH | Ensure filesystem integrity is regularly checked | timer" 66 | when: amazon2cis_aide_scan == "timer" 67 | ansible.builtin.systemd: 68 | name: "{{ item.name }}" 69 | enabled: true 70 | state: "{{ item.state | default(omit)}}" 71 | loop: 72 | - { name: 'aidecheck.service' } 73 | - { name: 'aidecheck.timer', state: started } 74 | -------------------------------------------------------------------------------- /tasks/section_5/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # 5.1 Configure Logging 4 | - name: "SECTION | 5.1.1.x | Configure rsyslog" 5 | when: amazon2cis_syslog == 'rsyslog' 6 | ansible.builtin.import_tasks: 7 | file: cis_5.1.1.x.yml 8 | 9 | - name: "SECTION | 5.1.2.x | Configure journald" 10 | when: amazon2cis_syslog == 'journald' 11 | ansible.builtin.import_tasks: 12 | file: cis_5.1.2.x.yml 13 | 14 | - name: "SECTION | 5.1.3 | Configure logile perms" 15 | ansible.builtin.import_tasks: 16 | file: cis_5.1.3.yml 17 | 18 | - name: "SECTION | 5.1.4 | Configure logrotate" 19 | ansible.builtin.import_tasks: 20 | file: cis_5.1.4.yml 21 | 22 | # 5.2 Configure System Accounting (auditd) 23 | - name: "SECTION | 5.2.1 | Ensure auditing is enabled" 24 | ansible.builtin.import_tasks: 25 | file: cis_5.2.1.x.yml 26 | 27 | - name: "SECTION | 5.2.2 | Configure Data Retention" 28 | ansible.builtin.import_tasks: 29 | file: cis_5.2.2.x.yml 30 | 31 | - name: "SECTION | 5.2.3.x | Configure auditd rules" 32 | ansible.builtin.import_tasks: 33 | file: cis_5.2.3.x.yml 34 | 35 | - name: "SECTION | 5.2.4.x | Audit file permissions" 36 | ansible.builtin.import_tasks: 37 | file: cis_5.2.4.x.yml 38 | 39 | - name: "SECTION | 5.3.x | Aide" 40 | ansible.builtin.import_tasks: 41 | file: cis_5.3.x.yml 42 | when: amazon2cis_config_aide 43 | -------------------------------------------------------------------------------- /tasks/section_6/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: "SECTION | 6.1 | System File Permissions" 4 | ansible.builtin.import_tasks: 5 | file: cis_6.1.x.yml 6 | 7 | - name: "SECTION | 6.2 | User and Group Settings" 8 | ansible.builtin.import_tasks: 9 | file: cis_6.2.x.yml 10 | -------------------------------------------------------------------------------- /tasks/warning_facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # This task is used to create variables used in giving a warning summary for manual tasks 4 | # that need attention 5 | # 6 | # The warn_control_list and warn_count vars start life in vars/main.yml but get updated 7 | # as the tasks that have a warning complete 8 | # 9 | # Those two variables are used in the tasks/main.yml to display a list of warnings 10 | # 11 | # warn_control_id is set within the task itself and has the control ID as the value 12 | # 13 | # warn_control_list is the main variable to be used and is a list made up of the warn_control_id’s 14 | # 15 | # warn_count the main variable for the number of warnings and each time a warn_control_id is added 16 | # the count increases by a value of 1 17 | - name: "{{ warn_control_id }} | WARNING | Set fact for manual task warning." 18 | ansible.builtin.set_fact: 19 | warn_control_list: "{{ warn_control_list }} [{{ warn_control_id }}]" 20 | warn_count: "{{ warn_count | int + 1 }}" 21 | -------------------------------------------------------------------------------- /templates/audit/99_auditd.rules.j2: -------------------------------------------------------------------------------- 1 | ## This file is managed by Ansible, YOUR CHANGES WILL BE LOST! 2 | 3 | # This template will set all of the auditd configurations via a handler in the role in one task instead of individually 4 | {% if amazon2cis_rule_5_2_3_1 %} 5 | -w /etc/sudoers -p wa -k scope 6 | -w /etc/sudoers.d/ -p wa -k scope 7 | {% endif %} 8 | {% if amazon2cis_rule_5_2_3_2 %} 9 | -a always,exit -F arch=b64 -C euid!=uid -F auid!=unset -S execve -k user_emulation 10 | -a always,exit -F arch=b32 -C euid!=uid -F auid!=unset -S execve -k user_emulation 11 | {% endif %} 12 | {% if amazon2cis_rule_5_2_3_3 %} 13 | -w {{ amazon2cis_sudolog_location }} -p wa -k sudo_log_file 14 | {% endif %} 15 | {% if amazon2cis_rule_5_2_3_4 %} 16 | -a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k time-change 17 | -a always,exit -F arch=b32 -S adjtimex,settimeofday,clock_settime -k time-change 18 | -w /etc/localtime -p wa -k time-change 19 | {% endif %} 20 | {% if amazon2cis_rule_5_2_3_5 %} 21 | -a always,exit -F arch=b64 -S sethostname,setdomainname -F key=system-locale 22 | -a always,exit -F arch=b32 -S sethostname,setdomainname -F key=system-locale 23 | -w /etc/issue -p wa -k system-locale 24 | -w /etc/issue.net -p wa -k system-locale 25 | -w /etc/hosts -p wa -k system-locale 26 | -w /etc/sysconfig/network -p wa -k system-locale 27 | -w /etc/sysconfig/network-scripts/ -p wa -k system-locale 28 | {% endif %} 29 | {% if amazon2cis_rule_5_2_3_6 %} 30 | {% for proc in priv_procs.stdout_lines -%} 31 | -a always,exit -F path={{ proc }} -F perm=x -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -k privileged 32 | {% endfor %} 33 | {% endif %} 34 | {% if amazon2cis_rule_5_2_3_7 %} 35 | -a always,exit -F arch=b64 -S creat,open,openat,truncate,ftruncate -F exit=-EACCES -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -F key=access 36 | -a always,exit -F arch=b64 -S creat,open,openat,truncate,ftruncate -F exit=-EPERM -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -F key=access 37 | -a always,exit -F arch=b32 -S creat,open,openat,truncate,ftruncate -F exit=-EACCES -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -F key=access 38 | -a always,exit -F arch=b32 -S creat,open,openat,truncate,ftruncate -F exit=-EPERM -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -F key=access 39 | {% endif %} 40 | {% if amazon2cis_rule_5_2_3_8 %} 41 | -w /etc/group -p wa -k identity 42 | -w /etc/passwd -p wa -k identity 43 | -w /etc/gshadow -p wa -k identity 44 | -w /etc/shadow -p wa -k identity 45 | -w /etc/security/opasswd -p wa -k identity 46 | {% endif %} 47 | {% if amazon2cis_rule_5_2_3_9 %} 48 | -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -F key=perm_mod 49 | -a always,exit -F arch=b64 -S chown,fchown,lchown,fchownat -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -F key=perm_mod 50 | -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -F key=perm_mod 51 | -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -F key=perm_mod 52 | -a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -F key=perm_mod 53 | -a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -F key=perm_mod 54 | {% endif %} 55 | {% if amazon2cis_rule_5_2_3_10 %} 56 | -a always,exit -F arch=b32 -S mount -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -k mounts 57 | -a always,exit -F arch=b64 -S mount -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -k mounts 58 | {% endif %} 59 | {% if amazon2cis_rule_5_2_3_11 %} 60 | -w /var/run/utmp -p wa -k session 61 | -w /var/log/wtmp -p wa -k session 62 | -w /var/log/btmp -p wa -k session 63 | {% endif %} 64 | {% if amazon2cis_rule_5_2_3_12 %} 65 | -w /var/log/lastlog -p wa -k logins 66 | -w /var/run/faillock -p wa -k logins 67 | {% endif %} 68 | {% if amazon2cis_rule_5_2_3_13 %} 69 | -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -F key=delete 70 | -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -F key=delete 71 | {% endif %} 72 | {% if amazon2cis_rule_5_2_3_14 %} 73 | -w /etc/selinux/ -p wa -k MAC-policy 74 | -w /usr/share/selinux/ -p wa -k MAC-policy 75 | {% endif %} 76 | {% if amazon2cis_rule_5_2_3_15 %} 77 | -a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -k perm_chng 78 | {% endif %} 79 | {% if amazon2cis_rule_5_2_3_16 %} 80 | -a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -k perm_chng 81 | {% endif %} 82 | {% if amazon2cis_rule_5_2_3_17 %} 83 | -a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -k perm_chng 84 | {% endif %} 85 | {% if amazon2cis_rule_5_2_3_18 %} 86 | -a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -k usermod 87 | {% endif %} 88 | {% if amazon2cis_rule_5_2_3_19 %} 89 | -a always,exit -F arch=b32 -S init_module,finit_module,delete_module,create_module,query_module -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -k kernel_modules 90 | -a always,exit -F arch=b64 -S init_module,finit_module,delete_module,create_module,query_module -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -k kernel_modules 91 | -a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>={{ amazon2cis_uid_min }} -F auid!=unset -k kernel_modules 92 | {% endif %} 93 | {% if amazon2cis_rule_5_2_3_20 %} 94 | -e 2 95 | {% endif %} 96 | -------------------------------------------------------------------------------- /templates/chrony.conf.j2: -------------------------------------------------------------------------------- 1 | # This the default chrony.conf file for the Debian chrony package. After 2 | # editing this file use the command 'invoke-rc.d chrony restart' to make 3 | # your changes take effect. John Hasler 1998-2008 4 | 5 | # See www.pool.ntp.org for an explanation of these servers. Please 6 | # consider joining the project if possible. If you can't or don't want to 7 | # use these servers I suggest that you try your ISP's nameservers. We mark 8 | # the servers 'offline' so that chronyd won't try to connect when the link 9 | # is down. Scripts in /etc/ppp/ip-up.d and /etc/ppp/ip-down.d use chronyc 10 | # commands to switch it on when a dialup link comes up and off when it goes 11 | # down. Code in /etc/init.d/chrony attempts to determine whether or not 12 | # the link is up at boot time and set the online status accordingly. If 13 | # you have an always-on connection such as cable omit the 'offline' 14 | # directive and chronyd will default to online. 15 | # 16 | # Note that if Chrony tries to go "online" and dns lookup of the servers 17 | # fails they will be discarded. Thus under some circumstances it is 18 | # better to use IP numbers than host names. 19 | 20 | {% for server in amazon2cis_time_synchronization_servers -%} 21 | server {{ server }} {{ amazon2cis_chrony_server_options }} 22 | {% endfor %} 23 | 24 | # Look here for the admin password needed for chronyc. The initial 25 | # password is generated by a random process at install time. You may 26 | # change it if you wish. 27 | 28 | keyfile /etc/chrony/chrony.keys 29 | 30 | # Set runtime command key. Note that if you change the key (not the 31 | # password) to anything other than 1 you will need to edit 32 | # /etc/ppp/ip-up.d/chrony, /etc/ppp/ip-down.d/chrony, /etc/init.d/chrony 33 | # and /etc/cron.weekly/chrony as these scripts use it to get the password. 34 | 35 | commandkey 1 36 | 37 | # I moved the driftfile to /var/lib/chrony to comply with the Debian 38 | # filesystem standard. 39 | 40 | driftfile /var/lib/chrony/chrony.drift 41 | 42 | # Comment this line out to turn off logging. 43 | 44 | log tracking measurements statistics 45 | logdir /var/log/chrony 46 | 47 | # Stop bad estimates upsetting machine clock. 48 | 49 | maxupdateskew 100.0 50 | 51 | # Dump measurements when daemon exits. 52 | 53 | dumponexit 54 | 55 | # Specify directory for dumping measurements. 56 | 57 | dumpdir /var/lib/chrony 58 | 59 | # Let computer be a server when it is unsynchronised. 60 | 61 | local stratum 10 62 | 63 | # Allow computers on the unrouted nets to use the server. 64 | 65 | #allow 10/8 66 | #allow 192.168/16 67 | #allow 172.16/12 68 | 69 | # This directive forces `chronyd' to send a message to syslog if it 70 | # makes a system clock adjustment larger than a threshold value in seconds. 71 | 72 | logchange 0.5 73 | 74 | # This directive defines an email address to which mail should be sent 75 | # if chronyd applies a correction exceeding a particular threshold to the 76 | # system clock. 77 | 78 | # mailonchange root@localhost 0.5 79 | 80 | # This directive tells chrony to regulate the real-time clock and tells it 81 | # Where to store related data. It may not work on some newer motherboards 82 | # that use the HPET real-time clock. It requires enhanced real-time 83 | # support in the kernel. I've commented it out because with certain 84 | # combinations of motherboard and kernel it is reported to cause lockups. 85 | 86 | # rtcfile /var/lib/chrony/chrony.rtc 87 | 88 | # If the last line of this file reads 'rtconutc' chrony will assume that 89 | # the CMOS clock is on UTC (GMT). If it reads '# rtconutc' or is absent 90 | # chrony will assume local time. The line (if any) was written by the 91 | # chrony postinst based on what it found in /etc/default/rcS. You may 92 | # change it if necessary. 93 | rtconutc 94 | -------------------------------------------------------------------------------- /templates/etc/ansible/compliance_facts.j2: -------------------------------------------------------------------------------- 1 | # CIS Hardening Carried out 2 | # Added as part of ansible-lockdown CIS baseline 3 | # provided by Mindpoint Group - A Tyto Athene Company 4 | 5 | [lockdown_details] 6 | # Benchmark release 7 | Benchmark_release = CIS-{{ benchmark_version }} 8 | Benchmark_run_date = {{ '%Y-%m-%d - %H:%M:%S' | ansible.builtin.strftime }} 9 | # If options set (doesn't mean it ran all controls) 10 | level_1_hardening_enabled = {{ amazon2cis_level_1 }} 11 | level_2_hardening_enabled = {{ amazon2cis_level_2 }} 12 | 13 | {% if ansible_run_tags | length > 0 %} 14 | # If tags used to stipulate run level 15 | {% if 'level1-server' in ansible_run_tags %} 16 | Level_1_Server_tag_run = true 17 | {% endif %} 18 | {% if 'level2-server' in ansible_run_tags %} 19 | Level_2_Server_tag_run = true 20 | {% endif %} 21 | {% if 'level1-workstation' in ansible_run_tags %} 22 | Level_1_workstation_tag_run = true 23 | {% endif %} 24 | {% if 'level2-workstation' in ansible_run_tags %} 25 | Level_2_workstation_tag_run = true 26 | {% endif %} 27 | {% endif %} 28 | 29 | [lockdown_audit_details] 30 | {% if run_audit %} 31 | # Audit run 32 | audit_run_date = {{ '%Y-%m-%d - %H:%M:%S' | ansible.builtin.strftime }} 33 | audit_file_local_location = {{ audit_log_dir }} 34 | {% if not audit_only %} 35 | audit_summary = {{ post_audit_results }} 36 | {% endif %} 37 | {% if fetch_audit_output %} 38 | audit_files_centralized_location = {{ audit_output_destination }} 39 | {% endif %} 40 | {% endif %} 41 | -------------------------------------------------------------------------------- /templates/etc/issue.j2: -------------------------------------------------------------------------------- 1 | {{ amazon2cis_warning_banner }} 2 | -------------------------------------------------------------------------------- /templates/etc/issue.net.j2: -------------------------------------------------------------------------------- 1 | {{ amazon2cis_warning_banner }} 2 | -------------------------------------------------------------------------------- /templates/etc/motd.j2: -------------------------------------------------------------------------------- 1 | {{ amazon2cis_warning_banner }} 2 | -------------------------------------------------------------------------------- /templates/etc/systemd/system/tmp.mount.j2: -------------------------------------------------------------------------------- 1 | ## This file is managed by Ansible, YOUR CHANGED WILL BE LOST! 2 | 3 | 4 | [Unit] 5 | Description=Temporary Directory (/tmp) 6 | Documentation=man:hier(7) 7 | Documentation=https://www.freedesktop.org/wiki/Software/systemd/APIFileSystems 8 | ConditionPathIsSymbolicLink=!/tmp 9 | DefaultDependencies=no 10 | Conflicts=umount.target 11 | Before=local-fs.target umount.target 12 | After=swap.target 13 | 14 | [Mount] 15 | What=tmpfs 16 | Where=/tmp 17 | Type=tmpfs 18 | Options=mode=1777,strictatime,{% if amazon2cis_rule_1_1_2_1_2 %}nodev,{% endif %}{% if amazon2cis_rule_1_1_2_1_3 %}nosuid,{% endif %}{% if amazon2cis_rule_1_1_2_1_4 %}noexec{% endif %} 19 | 20 | # Make 'systemctl enable tmp.mount' work: 21 | [Install] 22 | WantedBy=local-fs.target 23 | -------------------------------------------------------------------------------- /templates/etc/tmp_mount.j2: -------------------------------------------------------------------------------- 1 | # This file is part of systemd. 2 | # 3 | # systemd is free software; you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published by 5 | # the Free Software Foundation; either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | 8 | [Unit] 9 | Description=Temporary Directory 10 | Documentation=man:hier(7) 11 | Documentation=http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems 12 | ConditionPathIsSymbolicLink=!/tmp 13 | DefaultDependencies=no 14 | Conflicts=umount.target 15 | Before=local-fs.target umount.target 16 | 17 | [Mount] 18 | What=tmpfs 19 | Where=/tmp 20 | Type=tmpfs 21 | Options=mode=1777,strictatime,{% if amazon2cis_rule_1_1_3 %}noexec,{% endif %}{% if amazon2cis_rule_1_1_4 %}nodev,{% endif %}{% if amazon2cis_rule_1_1_5 %}nosuid{% endif %} 22 | 23 | # Make 'systemctl enable tmp.mount' work: 24 | [Install] 25 | WantedBy=local-fs.target 26 | -------------------------------------------------------------------------------- /templates/ntp.conf.j2: -------------------------------------------------------------------------------- 1 | # For more information about this file, see the man pages 2 | # ntp.conf(5), ntp_acc(5), ntp_auth(5), ntp_clock(5), ntp_misc(5), ntp_mon(5). 3 | 4 | driftfile /var/lib/ntp/drift 5 | 6 | # Permit time synchronization with our time source, but do not 7 | # permit the source to query or modify the service on this system. 8 | #restrict default nomodify notrap nopeer noquery 9 | restrict -4 default kod nomodify notrap nopeer noquery 10 | restrict -6 default kod nomodify notrap nopeer noquery 11 | 12 | # Permit all access over the loopback interface. This could 13 | # be tightened as well, but to do so would effect some of 14 | # the administrative functions. 15 | restrict 127.0.0.1 16 | restrict ::1 17 | 18 | # Hosts on local network are less restricted. 19 | #restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap 20 | 21 | # Use public servers from the pool.ntp.org project. 22 | # Please consider joining the pool (http://www.pool.ntp.org/join.html). 23 | {% for server in amazon2cis_time_synchronization_servers -%} 24 | server {{ server }} {{ amazon2cis_ntp_server_options }} 25 | {% endfor %} 26 | 27 | #broadcast 192.168.1.255 autokey # broadcast server 28 | #broadcastclient # broadcast client 29 | #broadcast 224.0.1.1 autokey # multicast server 30 | #multicastclient 224.0.1.1 # multicast client 31 | #manycastserver 239.255.254.254 # manycast server 32 | #manycastclient 239.255.254.254 autokey # manycast client 33 | 34 | # Enable public key cryptography. 35 | #crypto 36 | 37 | includefile /etc/ntp/crypto/pw 38 | 39 | # Key file containing the keys and key identifiers used when operating 40 | # with symmetric key cryptography. 41 | keys /etc/ntp/keys 42 | 43 | # Specify the key identifiers which are trusted. 44 | #trustedkey 4 8 42 45 | 46 | # Specify the key identifier to use with the ntpdc utility. 47 | #requestkey 8 48 | 49 | # Specify the key identifier to use with the ntpq utility. 50 | #controlkey 8 51 | 52 | # Enable writing of statistics records. 53 | #statistics clockstats cryptostats loopstats peerstats 54 | 55 | # Disable the monitoring facility to prevent amplification attacks using ntpdc 56 | # monlist command when default restrict does not include the noquery flag. See 57 | # CVE-2013-5211 for more details. 58 | # Note: Monitoring will not be disabled with the limited restriction flag. 59 | disable monitor 60 | -------------------------------------------------------------------------------- /vars/audit.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | #### Audit Configuration Settings #### 4 | 5 | # Timeout for those cmds that take longer to run where timeout set 6 | audit_cmd_timeout: 120000 7 | 8 | # if get_audit_binary_method == download change accordingly 9 | audit_bin_url: "https://github.com/goss-org/goss/releases/download/{{ audit_bin_version.release }}/goss-linux-" 10 | 11 | ### Goss Audit Benchmark file ### 12 | ## managed by the control audit_content 13 | # git 14 | audit_file_git: "https://github.com/ansible-lockdown/{{ benchmark }}-Audit.git" 15 | audit_git_version: "benchmark_{{ benchmark_version }}" 16 | 17 | ## Goss configuration information 18 | # Where the goss audit configuration will be stored - NOTE benchmark-audit is expected 19 | audit_conf_dir: "{{ audit_conf_dest | default('/opt') }}/{{ benchmark }}-Audit" 20 | 21 | # If changed these can affect other products 22 | pre_audit_outfile: "{{ audit_log_dir }}/{{ ansible_facts.hostname }}-{{ benchmark }}-{{ benchmark_version }}_pre_scan_{{ ansible_facts.date_time.epoch }}.{{ audit_format }}" 23 | post_audit_outfile: "{{ audit_log_dir }}/{{ ansible_facts.hostname }}-{{ benchmark }}-{{ benchmark_version }}_post_scan_{{ ansible_facts.date_time.epoch }}.{{ audit_format }}" 24 | 25 | ## The following should not need changing 26 | 27 | ### Audit binary settings ### 28 | audit_bin_version: 29 | release: v0.4.4 30 | AMD64_checksum: 'sha256:1c4f54b22fde9d4d5687939abc2606b0660a5d14a98afcd09b04b793d69acdc5' 31 | audit_bin_path: /usr/local/bin/ 32 | audit_bin: "{{ audit_bin_path }}goss" 33 | audit_format: json 34 | 35 | audit_vars_path: "{{ audit_conf_dir }}/vars/{{ ansible_facts.hostname }}.yml" 36 | audit_results: | 37 | The{% if not audit_only %} pre remediation{% endif %} audit results are: {{ pre_audit_results }} 38 | {% if not audit_only %}The post remediation audit results are: {{ post_audit_results }}{% endif %} 39 | 40 | Full breakdown can be found in {{ audit_log_dir }} 41 | -------------------------------------------------------------------------------- /vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for amazon linux 2 3 | 4 | min_ansible_version: 2.11.1 5 | 6 | reboot_required: false 7 | change_requires_reboot: false 8 | update_audit_template: false 9 | 10 | # Used to control warning summary 11 | warn_control_list: "" 12 | warn_count: 0 13 | --------------------------------------------------------------------------------