Compare commits

..

14 commits
devel ... 2.0.0

Author SHA1 Message Date
uk-bolly
f4a0bca52a
Merge pull request #290 from ansible-lockdown/devel
CIS V2 release to main
2025-02-14 10:44:12 +00:00
uk-bolly
ef2b7dca5d
Merge pull request #267 from ansible-lockdown/devel
CIS v1.0.0 final release to main
2024-12-19 15:07:56 +00:00
uk-bolly
81a929961a
Merge pull request #259 from ansible-lockdown/devel
CIS v1.0.0 updates Nov 2024
2024-11-19 18:11:52 +00:00
uk-bolly
16cb6a4617
Merge pull request #235 from ansible-lockdown/devel
rhel9-cis main release v1.0.0
2024-09-10 15:45:16 +01:00
uk-bolly
151896e113
Merge pull request #213 from ansible-lockdown/devel
Update to galaxy meta
2024-06-11 13:02:59 +01:00
uk-bolly
306eb59b88
Merge pull request #210 from ansible-lockdown/devel
Release to main
2024-06-10 12:49:41 +01:00
uk-bolly
7661bc0963
Merge pull request #205 from ansible-lockdown/devel
Release to main
2024-05-01 13:53:19 +01:00
uk-bolly
00e6f196b5
Merge pull request #89 from ansible-lockdown/devel
workflow check run
2023-08-10 14:25:08 +01:00
uk-bolly
4567a0baad
Merge pull request #86 from ansible-lockdown/devel
Readme layout update
2023-08-09 16:08:19 +01:00
uk-bolly
10dc297e9a
Merge pull request #84 from ansible-lockdown/devel
devel to main release
2023-08-09 14:34:53 +01:00
uk-bolly
21a886a81c
Merge pull request #64 from ansible-lockdown/devel
Devel to main - bug fixes
2023-06-06 14:40:39 +01:00
uk-bolly
759bbbad7e
Merge pull request #49 from ansible-lockdown/devel
Galaxy Compliance
2023-03-21 21:11:51 +00:00
uk-bolly
8bbccd6b62
Merge pull request #47 from ansible-lockdown/devel
Merge to Main galaxy workflow
2023-03-21 16:35:53 +00:00
uk-bolly
beaeb3a181
Merge pull request #45 from ansible-lockdown/devel
Initial 1.0 release CIS 1.0
2023-03-21 15:39:53 +00:00
59 changed files with 1049 additions and 1712 deletions

View file

@ -1,17 +0,0 @@
---
name: Add Repo Issue to ALD GH project
on:
issues:
types:
- opened
- reopened
- transferred
jobs:
add-to-project:
runs-on: ubuntu-latest
steps:
- uses: actions/add-to-project@main
with:
project-url: https://github.com/orgs/ansible-lockdown/projects/1
github-token: ${{ secrets.ALD_GH_PROJECT }}

View file

@ -1,54 +0,0 @@
---
# GitHub schedules all cron jobs in UTC.
# ──────────────────────────────────────────────────────────────────────────────
# Schedule:
# - '0 13 * * *' runs at 13:00 UTC every day.
# - This corresponds to:
# • 9:00 AM Eastern **during Daylight Saving Time** (mid-Mar → early-Nov)
# • 8:00 AM Eastern **during Standard Time** (early-Nov → mid-Mar)
#
# Job routing:
# - call-benchmark-tracker:
# • Runs on manual dispatch, and on pushes to the 'latest' branch.
# - call-monitor-promotions:
# • Runs on schedule or manual dispatch **only in repos named ansible-lockdown/Private-***.
# • Skips automatically in public repos (e.g., Windows-2022-CIS) to avoid false failures.
#
# Defense-in-depth:
# - The called promotion workflow may still keep its own guard to ensure only Private-* repos execute it.
name: Central Benchmark Orchestrator
on:
push:
branches:
- latest
schedule:
- cron: '0 13 * * *' # 13:00 UTC → 9 AM ET (DST) / 8 AM ET (Standard Time)
workflow_dispatch:
jobs:
call-benchmark-tracker:
# Run on manual dispatch OR when 'latest' branch receives a push
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref_name == 'latest')
name: Start Benchmark Tracker
uses: ansible-lockdown/github_linux_IaC/.github/workflows/benchmark_track.yml@self_hosted
with:
repo_name: ${{ github.repository }}
secrets:
TEAMS_WEBHOOK_URL: ${{ secrets.TEAMS_WEBHOOK_URL }}
BADGE_PUSH_TOKEN: ${{ secrets.BADGE_PUSH_TOKEN }}
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
call-monitor-promotions:
# Run on schedule or manual dispatch, but only for Private-* repos
if: (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && startsWith(github.repository, 'ansible-lockdown/Private-')
name: Monitor Promotions and Auto-Promote
uses: ansible-lockdown/github_linux_IaC/.github/workflows/benchmark_promote.yml@self_hosted
with:
repo_name: ${{ github.repository }}
secrets:
TEAMS_WEBHOOK_URL: ${{ secrets.TEAMS_WEBHOOK_URL }}
BADGE_PUSH_TOKEN: ${{ secrets.BADGE_PUSH_TOKEN }}
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}

View file

@ -4,159 +4,155 @@
on: # yamllint disable-line rule:truthy
pull_request_target:
types: [opened, reopened, synchronize]
branches:
- devel
- benchmark*
paths:
- '**.yml'
- '**.sh'
- '**.j2'
- '**.ps1'
- '**.cfg'
types: [opened, reopened, synchronize]
branches:
- devel
paths:
- '**.yml'
- '**.sh'
- '**.j2'
- '**.ps1'
- '**.cfg'
# Allow manual running of workflow
workflow_dispatch:
# Allow permissions for AWS auth
permissions:
id-token: write
contents: read
pull-requests: read
# A workflow run is made up of one or more jobs
# that can run sequentially or in parallel
jobs:
# This will create messages for first time contributers and direct them to the Discord server
welcome:
runs-on: ubuntu-latest
welcome:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/first-interaction@main
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
pr-message: |-
Congrats on opening your first pull request and thank you for taking the time to help improve Ansible-Lockdown!
Please join in the conversation happening on the [Discord Server](https://www.lockdownenterprise.com/discord) as well.
steps:
- uses: actions/first-interaction@main
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
issue_message: |-
Congrats on opening your first issue and thank you for taking the time to help improve Ansible-Lockdown!
Please join in the conversation happening on the [Discord Server](https://www.lockdownenterprise.com/discord) as well.
pr_message: |-
Congrats on opening your first pull request and thank you for taking the time to help improve Ansible-Lockdown!
Please join in the conversation happening on the [Discord Server](https://www.lockdownenterprise.com/discord) as well.
# This workflow contains a single job that tests the playbook
playbook-test:
# The type of runner that the job will run on
runs-on: self-hosted
env:
ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }}
# Imported as a variable by terraform
TF_VAR_repository: ${{ github.event.repository.name }}
AWS_REGION: "us-east-1"
ANSIBLE_VERSION: ${{ vars.ANSIBLE_RUNNER_VERSION }}
defaults:
run:
shell: bash
working-directory: .github/workflows/github_linux_IaC
# working-directory: .github/workflows
# This workflow contains a single job that tests the playbook
playbook-test:
# The type of runner that the job will run on
runs-on: self-hosted
steps:
# Allow permissions for AWS auth
permissions:
id-token: write
contents: read
pull-requests: read
- name: Git clone the lockdown repository to test
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
env:
ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }}
# Imported as a variable by terraform
TF_VAR_repository: ${{ github.event.repository.name }}
AWS_REGION: "us-east-1"
ANSIBLE_VERSION: ${{ vars.ANSIBLE_RUNNER_VERSION }}
defaults:
run:
shell: bash
working-directory: .github/workflows/github_linux_IaC
# working-directory: .github/workflows
- name: If a variable for IAC_BRANCH is set use that branch
working-directory: .github/workflows
run: |
if [ ${{ vars.IAC_BRANCH }} != '' ]; then
echo "IAC_BRANCH=${{ vars.IAC_BRANCH }}" >> $GITHUB_ENV
echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}"
else
echo IAC_BRANCH=main >> $GITHUB_ENV
fi
steps:
# Pull in terraform code for linux servers
- name: Clone GitHub IaC plan
uses: actions/checkout@v4
with:
repository: ansible-lockdown/github_linux_IaC
path: .github/workflows/github_linux_IaC
ref: ${{ env.IAC_BRANCH }}
- name: Git clone the lockdown repository to test
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
# Uses dedicated restricted role and policy to enable this only for this task
# No credentials are part of github for AWS auth
- name: configure aws credentials
uses: aws-actions/configure-aws-credentials@main
with:
role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }}
role-session-name: ${{ secrets.AWS_ROLE_SESSION }}
aws-region: ${{ env.AWS_REGION }}
- name: If a variable for IAC_BRANCH is set use that branch
working-directory: .github/workflows
run: |
if [ ${{ vars.IAC_BRANCH }} != '' ]; then
echo "IAC_BRANCH=${{ vars.IAC_BRANCH }}" >> $GITHUB_ENV
echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}"
else
echo IAC_BRANCH=main >> $GITHUB_ENV
fi
- name: DEBUG - Show IaC files
if: env.ENABLE_DEBUG == 'true'
run: |
echo "OSVAR = $OSVAR"
echo "benchmark_type = $benchmark_type"
echo "PRIVSUBNET_ID = $AWS_PRIVSUBNET_ID"
echo "VPC_ID" = $AWS_VPC_SECGRP_ID"
pwd
ls
env:
# Imported from GitHub variables this is used to load the relevant OS.tfvars file
OSVAR: ${{ vars.OSVAR }}
benchmark_type: ${{ vars.BENCHMARK_TYPE }}
PRIVSUBNET_ID: ${{ secrets.AWS_PRIVSUBNET_ID }}
VPC_ID: ${{ secrets.AWS_VPC_SECGRP_ID }}
# Pull in terraform code for linux servers
- name: Clone GitHub IaC plan
uses: actions/checkout@v4
with:
repository: ansible-lockdown/github_linux_IaC
path: .github/workflows/github_linux_IaC
ref: ${{ env.IAC_BRANCH }}
- name: Tofu init
id: init
run: tofu init
env:
# Imported from GitHub variables this is used to load the relevant OS.tfvars file
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
# Uses dedicated restricted role and policy to enable this only for this task
# No credentials are part of github for AWS auth
- name: configure aws credentials
uses: aws-actions/configure-aws-credentials@main
with:
role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }}
role-session-name: ${{ secrets.AWS_ROLE_SESSION }}
aws-region: ${{ env.AWS_REGION }}
- name: Tofu validate
id: validate
run: tofu validate
env:
# Imported from GitHub variables this is used to load the relevant OS.tfvars file
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
- name: DEBUG - Show IaC files
if: env.ENABLE_DEBUG == 'true'
run: |
echo "OSVAR = $OSVAR"
echo "benchmark_type = $benchmark_type"
pwd
env:
# Imported from GitHub variables this is used to load the relevant OS.tfvars file
OSVAR: ${{ vars.OSVAR }}
benchmark_type: ${{ vars.BENCHMARK_TYPE }}
- name: Tofu init
id: init
run: tofu init
env:
# Imported from GitHub variables this is used to load the relevant OS.tfvars file
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
- name: Tofu validate
id: validate
run: tofu validate
env:
# Imported from GitHub variables this is used to load the relevant OS.tfvars file
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
- name: Tofu apply
id: apply
env:
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }}
TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }}
run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false
- name: Tofu apply
id: apply
env:
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }}
TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }}
run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false
## Debug Section
- name: DEBUG - Show Ansible hostfile
if: env.ENABLE_DEBUG == 'true'
run: cat hosts.yml
- name: DEBUG - Show Ansible hostfile
if: env.ENABLE_DEBUG == 'true'
run: cat hosts.yml
# Aws deployments taking a while to come up insert sleep or playbook fails
# Aws deployments taking a while to come up insert sleep or playbook fails
- name: Sleep to allow system to come up
run: sleep ${{ vars.BUILD_SLEEPTIME }}
- name: Sleep to allow system to come up
run: sleep ${{ vars.BUILD_SLEEPTIME }}
# Run the Ansible playbook
- name: Run_Ansible_Playbook
env:
ANSIBLE_HOST_KEY_CHECKING: "false"
ANSIBLE_DEPRECATION_WARNINGS: "false"
run: |
/opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml
# Run the Ansible playbook
- name: Run_Ansible_Playbook
env:
ANSIBLE_HOST_KEY_CHECKING: "false"
ANSIBLE_DEPRECATION_WARNINGS: "false"
run: |
/opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml
# Remove test system - User secrets to keep if necessary
# Remove test system - User secrets to keep if necessary
- name: Tofu Destroy
if: always() && env.ENABLE_DEBUG == 'false'
env:
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }}
TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }}
run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false
- name: Tofu Destroy
if: always() && env.ENABLE_DEBUG == 'false'
env:
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }}
TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }}
run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false

View file

@ -1,27 +0,0 @@
---
name: Export Private Repo Badges
# Use different minute offsets with the same hourly pattern:
# Repo Group Suggested Cron Expression Explanation
# Group A 0 */6 * * * Starts at top of hour
# Group B 10 */6 * * * Starts at 10 after
# And So On
on:
push:
branches:
- latest
schedule:
- cron: '0 */6 * * *'
workflow_dispatch:
jobs:
export-badges:
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'schedule' && startsWith(github.repository, 'ansible-lockdown/Private-')) || (github.event_name == 'push' && github.ref_name == 'latest')
uses: ansible-lockdown/github_linux_IaC/.github/workflows/export_badges_private.yml@self_hosted
with:
# Full org/repo path passed for GitHub API calls (e.g., ansible-lockdown/Private-Windows-2016-CIS)
repo_name: ${{ github.repository }}
secrets:
BADGE_PUSH_TOKEN: ${{ secrets.BADGE_PUSH_TOKEN }}

View file

@ -1,19 +0,0 @@
---
name: Export Public Repo Badges
on:
push:
branches:
- main
- devel
workflow_dispatch:
jobs:
export-badges:
if: github.repository_visibility == 'public' && (github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && (github.ref_name == 'devel' || github.ref_name == 'main')))
uses: ansible-lockdown/github_linux_IaC/.github/workflows/export_badges_public.yml@self_hosted
with:
repo_name: ${{ github.repository }}
secrets:
BADGE_PUSH_TOKEN: ${{ secrets.BADGE_PUSH_TOKEN }}

View file

@ -4,16 +4,15 @@
on: # yamllint disable-line rule:truthy
pull_request_target:
types: [opened, reopened, synchronize]
branches:
- main
- latest
paths:
- '**.yml'
- '**.sh'
- '**.j2'
- '**.ps1'
- '**.cfg'
types: [opened, reopened, synchronize]
branches:
- main
paths:
- '**.yml'
- '**.sh'
- '**.j2'
- '**.ps1'
- '**.cfg'
# Allow permissions for AWS auth
permissions:
@ -24,118 +23,122 @@
# A workflow run is made up of one or more jobs
# that can run sequentially or in parallel
jobs:
# This workflow contains a single job that tests the playbook
playbook-test:
# The type of runner that the job will run on
runs-on: self-hosted
env:
ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }}
# Imported as a variable by terraform
TF_VAR_repository: ${{ github.event.repository.name }}
AWS_REGION : "us-east-1"
ANSIBLE_VERSION: ${{ vars.ANSIBLE_RUNNER_VERSION }}
defaults:
run:
shell: bash
working-directory: .github/workflows/github_linux_IaC
# working-directory: .github/workflows
# This workflow contains a single job that tests the playbook
playbook-test:
# The type of runner that the job will run on
runs-on: self-hosted
env:
ENABLE_DEBUG: ${{ vars.ENABLE_DEBUG }}
# Imported as a variable by terraform
TF_VAR_repository: ${{ github.event.repository.name }}
AWS_REGION : "us-east-1"
ANSIBLE_VERSION: ${{ vars.ANSIBLE_RUNNER_VERSION }}
defaults:
run:
shell: bash
working-directory: .github/workflows/github_linux_IaC
# working-directory: .github/workflows
steps:
steps:
- name: Git clone the lockdown repository to test
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Git clone the lockdown repository to test
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: If a variable for IAC_BRANCH is set use that branch
working-directory: .github/workflows
run: |
if [ ${{ vars.IAC_BRANCH }} != '' ]; then
echo "IAC_BRANCH=${{ vars.IAC_BRANCH }}" >> $GITHUB_ENV
echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}"
else
echo IAC_BRANCH=main >> $GITHUB_ENV
fi
- name: If a variable for IAC_BRANCH is set use that branch
working-directory: .github/workflows
run: |
if [ ${{ vars.IAC_BRANCH }} != '' ]; then
echo "IAC_BRANCH=${{ vars.IAC_BRANCH }}" >> $GITHUB_ENV
echo "Pipeline using the following IAC branch ${{ vars.IAC_BRANCH }}"
else
echo IAC_BRANCH=main >> $GITHUB_ENV
fi
# Pull in terraform code for linux servers
- name: Clone GitHub IaC plan
uses: actions/checkout@v4
with:
repository: ansible-lockdown/github_linux_IaC
path: .github/workflows/github_linux_IaC
ref: ${{ env.IAC_BRANCH }}
# Pull in terraform code for linux servers
- name: Clone GitHub IaC plan
uses: actions/checkout@v4
with:
repository: ansible-lockdown/github_linux_IaC
path: .github/workflows/github_linux_IaC
ref: ${{ env.IAC_BRANCH }}
# Uses dedicated restricted role and policy to enable this only for this task
# No credentials are part of github for AWS auth
- name: configure aws credentials
uses: aws-actions/configure-aws-credentials@main
with:
role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }}
role-session-name: ${{ secrets.AWS_ROLE_SESSION }}
aws-region: ${{ env.AWS_REGION }}
# Uses dedicated restricted role and policy to enable this only for this task
# No credentials are part of github for AWS auth
- name: configure aws credentials
uses: aws-actions/configure-aws-credentials@main
with:
role-to-assume: ${{ secrets.AWS_ASSUME_ROLE }}
role-session-name: ${{ secrets.AWS_ROLE_SESSION }}
aws-region: ${{ env.AWS_REGION }}
- name: DEBUG - Show IaC files
if: env.ENABLE_DEBUG == 'true'
run: |
echo "OSVAR = $OSVAR"
echo "benchmark_type = $benchmark_type"
pwd
ls
env:
# Imported from GitHub variables this is used to load the relevant OS.tfvars file
OSVAR: ${{ vars.OSVAR }}
benchmark_type: ${{ vars.BENCHMARK_TYPE }}
- name: DEBUG - Show IaC files
if: env.ENABLE_DEBUG == 'true'
run: |
echo "OSVAR = $OSVAR"
echo "benchmark_type = $benchmark_type"
echo "PRIVSUBNET_ID = $AWS_PRIVSUBNET_ID"
echo "VPC_ID" = $AWS_VPC_SECGRP_ID"
pwd
ls
env:
# Imported from GitHub variables this is used to load the relevant OS.tfvars file
OSVAR: ${{ vars.OSVAR }}
benchmark_type: ${{ vars.BENCHMARK_TYPE }}
PRIVSUBNET_ID: ${{ secrets.AWS_PRIVSUBNET_ID }}
VPC_ID: ${{ secrets.AWS_VPC_SECGRP_ID }}
- name: Tofu init
id: init
run: tofu init
env:
# Imported from GitHub variables this is used to load the relevant OS.tfvars file
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
- name: Tofu init
id: init
run: tofu init
env:
# Imported from GitHub variables this is used to load the relevant OS.tfvars file
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
- name: Tofu validate
id: validate
run: tofu validate
env:
# Imported from GitHub variables this is used to load the relevant OS.tfvars file
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
- name: Tofu validate
id: validate
run: tofu validate
env:
# Imported from GitHub variables this is used to load the relevant OS.tfvars file
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
- name: Tofu apply
id: apply
env:
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }}
TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }}
run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false
- name: Tofu apply
id: apply
env:
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }}
TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }}
run: tofu apply -var-file "${OSVAR}.tfvars" --auto-approve -input=false
## Debug Section
- name: DEBUG - Show Ansible hostfile
if: env.ENABLE_DEBUG == 'true'
run: cat hosts.yml
- name: DEBUG - Show Ansible hostfile
if: env.ENABLE_DEBUG == 'true'
run: cat hosts.yml
# Aws deployments taking a while to come up insert sleep or playbook fails
# Aws deployments taking a while to come up insert sleep or playbook fails
- name: Sleep to allow system to come up
run: sleep ${{ vars.BUILD_SLEEPTIME }}
- name: Sleep to allow system to come up
run: sleep ${{ vars.BUILD_SLEEPTIME }}
# Run the Ansible playbook
- name: Run_Ansible_Playbook
env:
ANSIBLE_HOST_KEY_CHECKING: "false"
ANSIBLE_DEPRECATION_WARNINGS: "false"
run: |
/opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml
# Run the Ansible playbook
- name: Run_Ansible_Playbook
env:
ANSIBLE_HOST_KEY_CHECKING: "false"
ANSIBLE_DEPRECATION_WARNINGS: "false"
run: |
/opt/ansible_${{ env.ANSIBLE_VERSION }}_venv/bin/ansible-playbook -i hosts.yml --private-key ~/.ssh/le_runner ../../../site.yml
# Remove test system - User secrets to keep if necessary
# Remove test system - User secrets to keep if necessary
- name: Tofu Destroy
if: always() && env.ENABLE_DEBUG == 'false'
env:
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }}
TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }}
run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false
- name: Tofu Destroy
if: always() && env.ENABLE_DEBUG == 'false'
env:
OSVAR: ${{ vars.OSVAR }}
TF_VAR_benchmark_type: ${{ vars.BENCHMARK_TYPE }}
TF_VAR_privsubnet_id: ${{ secrets.AWS_PRIVSUBNET_ID }}
TF_VAR_vpc_secgrp_id: ${{ secrets.AWS_VPC_SECGRP_ID }}
run: tofu destroy -var-file "${OSVAR}.tfvars" --auto-approve -input=false

19
.github/workflows/update_galaxy.yml vendored Normal file
View file

@ -0,0 +1,19 @@
---
name: update galaxy
on:
push:
branches:
- main
jobs:
update_role:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Action Ansible Galaxy Release ${{ github.ref_name }}
uses: ansible-actions/ansible-galaxy-action@main
with:
galaxy_api_key: ${{ secrets.GALAXY_API_KEY }}

3
.gitignore vendored
View file

@ -46,6 +46,3 @@ benchparse/
# GitHub Action/Workflow files
.github/
# Precommit exclusions
.ansible/

View file

@ -7,7 +7,7 @@ ci:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
rev: v5.0.0
hooks:
# Safety
- id: detect-aws-credentials
@ -41,12 +41,12 @@ repos:
- id: detect-secrets
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.0
rev: v8.23.3
hooks:
- id: gitleaks
- repo: https://github.com/ansible-community/ansible-lint
rev: v25.12.2
rev: v25.1.2
hooks:
- id: ansible-lint
name: Ansible-lint
@ -65,7 +65,7 @@ repos:
# - ansible-core>=2.10.1
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.37.1 # or higher tag
rev: v1.35.1 # or higher tag
hooks:
- id: yamllint
name: Check YAML Lint

View file

@ -1,52 +1,5 @@
# Changes to rhel9CIS
## 2.0.4 - Based on CIS v2.0.0
- addressed issue #393 thank you to @fragglexarmy
- addressed issue #394 thank you to @dbeuker
- addressed issues #390 and #391 thanks to @polski-g
- addressed issue #398 & #399 thanks to trumbaut
- Added max-concurrent options for audit
- work flow updates
- audit logic improvements
- auditd template 2.19 compatible
- pre-commit updates
- #410 thanks to @kpi-nourman
- #413 thanks to @bbaassssiiee
## 2.0.3 - Based on CIS v2.0.0
- addressed issue #387, thank you @fragglexarmy
- addressed issue #382 to improve regex logic on 5.4.2.4
- improvement on crypto policy managed controls with var logic
- addressed issue #384 thank you @polski-g
- update command to shell module on tasks
- addressed issue 371 thanks to @bgro and kodebach
- addressed issue 350 thanks to @chrispipo
- addressed issue 364 thanks to @polski-g
- pre-commit update
## 2.0.2 - Based on CIS v2.0.0
- Update to audit_only to allow fetching results
- resolved false warning for fetch audit
- fix root user check
- Improved documentation and variable compilation for crypto policies
- Addresses #318 - Thank you @kodebach & @bgro
- Improved logic for 5.2.4 to exclude rhel9cis_sudoers_exclude_nopasswd_list in pre-check tasks/main.yml
## 2.0.1 - Based on CIS v2.0.0
- Thanks to @polski-g several issues and improvements added
- Improved testing for 50-redhat.conf for ssh
- 5.1.x regexp improvements
- Improved root password check
- egrep command changed to grep -E
## 2.0.0 - Based on CIS v2.0.0
- #322, #325 - thanks to @mindrb
- #320 - thanks to @anup-ad
## 1.1.6 - Based on CIS v1.0.0
- #190 - thanks to @ipruteanu-sie

195
README.md
View file

@ -6,96 +6,61 @@
---
## Public Repository 📣
![Org Stars](https://img.shields.io/github/stars/ansible-lockdown?label=Org%20Stars&style=social)
![Stars](https://img.shields.io/github/stars/ansible-lockdown/RHEL9-CIS?label=Repo%20Stars&style=social)
![Forks](https://img.shields.io/github/forks/ansible-lockdown/RHEL9-CIS?style=social)
![Followers](https://img.shields.io/github/followers/ansible-lockdown?style=social)
![followers](https://img.shields.io/github/followers/ansible-lockdown?style=social)
[![Twitter URL](https://img.shields.io/twitter/url/https/twitter.com/AnsibleLockdown.svg?style=social&label=Follow%20%40AnsibleLockdown)](https://twitter.com/AnsibleLockdown)
![Ansible Galaxy Quality](https://img.shields.io/ansible/quality/61781?label=Quality&&logo=ansible)
![Discord Badge](https://img.shields.io/discord/925818806838919229?logo=discord)
![License](https://img.shields.io/github/license/ansible-lockdown/RHEL9-CIS?label=License)
## Lint & Pre-Commit Tools 🔧
[![Pre-Commit.ci](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/RHEL9-CIS/pre-commit-ci.json)](https://results.pre-commit.ci/latest/github/ansible-lockdown/RHEL9-CIS/devel)
![YamlLint](https://img.shields.io/badge/yamllint-Present-brightgreen?style=flat&logo=yaml&logoColor=white)
![Ansible-Lint](https://img.shields.io/badge/ansible--lint-Present-brightgreen?style=flat&logo=ansible&logoColor=white)
## Community Release Information 📂
![Release Branch](https://img.shields.io/badge/Release%20Branch-Main-brightgreen)
![Release Tag](https://img.shields.io/github/v/tag/ansible-lockdown/RHEL9-CIS?label=Release%20Tag&&color=success)
![Main Release Date](https://img.shields.io/github/release-date/ansible-lockdown/RHEL9-CIS?label=Release%20Date)
![Benchmark Version Main](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/RHEL9-CIS/benchmark-version-main.json)
![Benchmark Version Devel](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/RHEL9-CIS/benchmark-version-devel.json)
![Release Tag](https://img.shields.io/github/v/release/ansible-lockdown/RHEL9-CIS)
![Release Date](https://img.shields.io/github/release-date/ansible-lockdown/RHEL9-CIS)
[![Main Pipeline Status](https://github.com/ansible-lockdown/RHEL9-CIS/actions/workflows/main_pipeline_validation.yml/badge.svg?)](https://github.com/ansible-lockdown/RHEL9-CIS/actions/workflows/main_pipeline_validation.yml)
[![Devel Pipeline Status](https://github.com/ansible-lockdown/RHEL9-CIS/actions/workflows/devel_pipeline_validation.yml/badge.svg?)](https://github.com/ansible-lockdown/RHEL9-CIS/actions/workflows/devel_pipeline_validation.yml)
![Devel Commits](https://img.shields.io/github/commit-activity/m/ansible-lockdown/RHEL9-CIS/devel?color=dark%20green&label=Devel%20Branch%20Commits)
![Open Issues](https://img.shields.io/github/issues-raw/ansible-lockdown/RHEL9-CIS?label=Open%20Issues)
![Closed Issues](https://img.shields.io/github/issues-closed-raw/ansible-lockdown/RHEL9-CIS?label=Closed%20Issues&&color=success)
![Issues Open](https://img.shields.io/github/issues-raw/ansible-lockdown/RHEL9-CIS?label=Open%20Issues)
![Issues Closed](https://img.shields.io/github/issues-closed-raw/ansible-lockdown/RHEL9-CIS?label=Closed%20Issues&&color=success)
![Pull Requests](https://img.shields.io/github/issues-pr/ansible-lockdown/RHEL9-CIS?label=Pull%20Requests)
---
## Subscriber Release Information 🔐
![Private Release Branch](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/Private-RHEL9-CIS/release-branch.json)
![Private Benchmark Version](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/Private-RHEL9-CIS/benchmark-version.json)
[![Private Remediate Pipeline](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/Private-RHEL9-CIS/remediate.json)](https://github.com/ansible-lockdown/Private-RHEL9-CIS/actions/workflows/main_pipeline_validation.yml)
[![Private GPO Pipeline](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/Private-RHEL9-CIS/gpo.json)](https://github.com/ansible-lockdown/Private-RHEL9-CIS/actions/workflows/main_pipeline_validation_gpo.yml)
![Private Pull Requests](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/Private-RHEL9-CIS/prs.json)
![Private Closed Issues](https://img.shields.io/endpoint?url=https://ansible-lockdown.github.io/github_linux_IaC/badges/Private-RHEL9-CIS/issues-closed.json)
![License](https://img.shields.io/github/license/ansible-lockdown/RHEL9-CIS?label=License)
---
## Looking for support? 🤝
### Community
[Lockdown Enterprise](https://www.lockdownenterprise.com#GH_AL_RHEL9-CIS)
[Ansible support](https://www.mindpointgroup.com/cybersecurity-products/ansible-counselor#GH_AL_RHEL9-CIS)
### Community 💬
On our [Discord Server](https://www.lockdownenterprise.com/discord) to ask questions, discuss features, or just chat with other Ansible-Lockdown users
Join us on our [Discord Server](https://www.lockdownenterprise.com/discord) to ask questions, discuss features, or just chat with other Ansible-Lockdown users.
---
## 🚨 Caution(s) 🚨
## Caution(s)
This role **will make changes to the system** which may have unintended consequences. This is not an auditing tool but rather a remediation tool to be used after an audit has been conducted.
- Testing is the most important thing you can do.
- Check Mode is not guaranteed! 🚫 The role will complete in check mode without errors, but it is not supported and should be used with caution.
- 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 RHEL9-CIS-Audit role or a compliance scanner should be used for compliance checking over check mode.
- This role was developed against a clean install of the Operating System. If you are implementing to an existing system please review this role for any site specific changes that are needed.
- To use release version please point to main branch and relevant release for the cis benchmark you wish to work with.
- To use release version please point to main branch and relevant release/tag for the cis benchmark you wish to work with.
- If moving across major releases e.g. v2.0.0 - v3.0.0 there are significant changes to the benchmarks and controls it is suggested to start as a new standard not to upgrade.
- Containers references vars/is_container.yml this is an example and to be updated for your requirements
- Did we mention testing??
---
## Coming From A Previous Release ⏪
CIS release always contains changes, it is highly recommended to review the new references and available variables. This have changed significantly since ansible-lockdown initial release.
This is now compatible with python3 if it is found to be the default interpreter. This does come with pre-requisites which it configures the system accordingly.
Further details can be seen in the [Changelog](./ChangeLog.md)
---
## Matching a security Level for CIS
It is possible to only run level 1 or level 2 controls for CIS.
It is possible to to only run level 1 or level 2 controls for CIS.
This is managed using tags:
- level1-server
@ -103,36 +68,16 @@ This is managed using tags:
- level2-server
- level2-workstation
The control found in defaults main also need to reflect this as this control the testing that takes place if you are using the audit component.
The control found in defaults main also need to reflect this as this control the testing thet takes place if you are using the audit component.
---
## Requirements ✅
## Coming from a previous release
**General:**
CIS release always contains changes, it is highly recommended to review the new references and available variables. This have changed significantly since ansible-lockdown initial release.
This is now compatible with python3 if it is found to be the default interpreter. This does come with pre-requisites which it configures the system accordingly.
- Basic knowledge of Ansible, below are some links to the Ansible documentation to help get started if you are unfamiliar with Ansible
Further details can be seen in the [Changelog](./Changelog.md)
- [Main Ansible documentation page](https://docs.ansible.com)
- [Ansible Getting Started](https://docs.ansible.com/ansible/latest/user_guide/intro_getting_started.html)
- [Tower User Guide](https://docs.ansible.com/ansible-tower/latest/html/userguide/index.html)
- [Ansible Community Info](https://docs.ansible.com/ansible/latest/community/index.html)
- Functioning Ansible and/or Tower Installed, configured, and running. This includes all of the base Ansible/Tower configurations, needed packages installed, and infrastructure setup.
- Please read through the tasks in this role to gain an understanding of what each control is doing. Some of the tasks are disruptive and can have unintended consequences in a live production system. Also familiarize yourself with the variables in the defaults/main.yml file.
**Technical Dependencies:**
RHEL Family OS 9
- Access to download or add the goss binary and content to the system if using auditing
(other options are available on how to get the content to the system.)
- Python3.8
- Ansible 2.12+
- python-def
- libselinux-python
---
## Auditing 🔍
## Auditing (new)
This can be turned on or off within the defaults/main.yml file with the variable run_audit. The value is false by default, please refer to the wiki for more details. The defaults file also populates the goss checks to check only the controls that have been enabled in the ansible role.
@ -163,7 +108,7 @@ PLAY RECAP *********************************************************************
default : ok=270 changed=23 unreachable=0 failed=0 skipped=140 rescued=0 ignored=0
```
## Documentation 📖
## Documentation
- [Read The Docs](https://ansible-lockdown.readthedocs.io/en/latest/)
- [Getting Started](https://www.lockdownenterprise.com/docs/getting-started-with-lockdown#GH_AL_RH9_cis)
@ -171,32 +116,38 @@ default : ok=270 changed=23 unreachable=0 failed=0 s
- [Per-Host Configuration](https://www.lockdownenterprise.com/docs/per-host-lockdown-enterprise-configuration#GH_AL_RH9_cis)
- [Getting the Most Out of the Role](https://www.lockdownenterprise.com/docs/get-the-most-out-of-lockdown-enterprise#GH_AL_RH9_cis)
## Requirements
**General:**
- Basic knowledge of Ansible, below are some links to the Ansible documentation to help get started if you are unfamiliar with Ansible
- [Main Ansible documentation page](https://docs.ansible.com)
- [Ansible Getting Started](https://docs.ansible.com/ansible/latest/user_guide/intro_getting_started.html)
- [Tower User Guide](https://docs.ansible.com/ansible-tower/latest/html/userguide/index.html)
- [Ansible Community Info](https://docs.ansible.com/ansible/latest/community/index.html)
- Functioning Ansible and/or Tower Installed, configured, and running. This includes all of the base Ansible/Tower configurations, needed packages installed, and infrastructure setup.
- Please read through the tasks in this role to gain an understanding of what each control is doing. Some of the tasks are disruptive and can have unintended consequences in a live production system. Also familiarize yourself with the variables in the defaults/main.yml file.
**Technical Dependencies:**
RHEL/AlmaLinux/Rocky/Oracle 9 - Other versions are not supported.
- Access to download or add the goss binary and content to the system if using auditing
(other options are available on how to get the content to the system.)
- Python3.8
- Ansible 2.12+
- python-def
- libselinux-python
## Role Variables
This role is designed that the end user should not have to edit the tasks themselves. All customizing should be done via the defaults/main.yml file or with extra vars within the project, job, workflow, etc.
## Tags 🏷️
## Tags
There are many tags available for added control precision. Each control has its own set of tags noting what level, what OS element it relates to, whether it's a patch or audit, and the rule number. Additionally, NIST references follow a specific conversion format for consistency and clarity.
There are many tags available for added control precision. Each control has it's own set of tags noting what level, if it's scored/notscored, what OS element it relates to, if it's a patch or audit, and the rule number.
### Conversion Format for NIST References:
1. Standard Prefix:
- All references are prefixed with "NIST".
2. Standard Types:
- "800-53" references are formatted as NIST800-53.
- "800-53r5" references are formatted as NIST800-53R5 (with 'R' capitalized).
- "800-171" references are formatted as NIST800-171.
3. Details:
- Section and subsection numbers use periods (.) for numeric separators.
- Parenthetical elements are separated by underscores (_), e.g., IA-5(1)(d) becomes IA-5_1_d.
- Subsection letters (e.g., "b") are appended with an underscore.
Below is an example of the tag section from a control within this role. Using this example if you set your run to skip all controls with the tag services, this task will be skipped. The opposite can also happen where you run only controls tagged with services.
```sh
@ -210,34 +161,33 @@ Below is an example of the tag section from a control within this role. Using th
- rule_2.2.4
```
## Community Contribution 🧑‍🤝‍🧑
## Community Contribution
We encourage you (the community) to contribute to this role. Please read the rules below.
- Your work is done in your own individual branch. Make sure to Signed-off-by and GPG sign all commits you intend to merge.
- Your work is done in your own individual branch. Make sure to Signed-off and GPG sign all commits you intend to merge.
- All community Pull Requests are pulled into the devel branch
- Pull Requests into devel will confirm your commits have a GPG signature, Signed-off-by, and a functional test before being approved
- Pull Requests into devel will confirm your commits have a GPG signature, Signed-off, and a functional test before being approved
- Once your changes are merged and a more detailed review is complete, an authorized member will merge your changes into the main branch for a new release
## Pipeline Testing 🔄
uses:
- ansible-core 2.16
- ansible collections - pulls in the latest version based on requirements file
- runs the audit using the devel branch
- This is an automated test that occurs on pull requests into devel
- self-hosted runners using OpenTofu
## Known Issues
Almalinux BaseOS, EPEL and many cloud providers repositories, do not allow gpgcheck(rule_1.2.1.2) or repo_gpgcheck (rule_1.2.1.3) this will cause issues during the playbook unless or a workaround is found.
## Pipeline Testing
## Local Testing 💻
uses:
### example
- ansible-core 2.12
- ansible collections - pulls in the latest version based on requirements file
- runs the audit using the devel branch
- This is an automated test that occurs on pull requests into devel
## Local Testing
Molecule can be used to work on this role and test in distinct _scenarios_.
### examples
```bash
molecule test -s default
@ -247,15 +197,24 @@ molecule verify -s localhost
local testing uses:
- ansible-core
- ansible 2.13.3
- molecule 4.0.1
- molecule-docker 2.0.0
- molecule-podman 2.0.2
- molecule-vagrant 1.0.0
- molecule-azure 0.5.0
## Added Extras
## Credits and Thanks 🙏
- [pre-commit](https://pre-commit.com) can be tested and can be run from within the directory
```sh
pre-commit run
```
## Credits and Thanks
Based on an original concept by Sam Doran
Massive thanks to the fantastic community and all its members.

File diff suppressed because it is too large Load diff

View file

@ -144,15 +144,6 @@
state: remounted
listen: "Remount /var/log/audit"
- name: "Remounting /boot/efi"
vars:
mount_point: '/boot/efi'
ansible.posix.mount:
path: "{{ mount_point }}"
state: remounted
notify: Change_requires_reboot
listen: "Remount /boot/efi"
- name: Reload sysctl
ansible.builtin.command: sysctl --system
changed_when: true
@ -186,7 +177,7 @@
- name: Update Crypto Policy
ansible.builtin.set_fact:
rhel9cis_full_crypto_policy: "{{ rhel9cis_crypto_policy }}{{ rhel9cis_crypto_policy_module }}{% if rhel9cis_additional_crypto_policy_module | length > 0 %}:{{ rhel9cis_additional_crypto_policy_module }}{% endif %}"
rhel9cis_full_crypto_policy: "{{ rhel9cis_crypto_policy }}{% if rhel9cis_crypto_policy_module | length > 0 %}{{ rhel9cis_crypto_policy_module }}{% endif %}"
notify: Set Crypto Policy
- name: Set Crypto Policy
@ -263,7 +254,7 @@
listen: Restart auditd
- name: Start auditd process
ansible.builtin.systemd:
ansible.builtin.systemd_service:
name: auditd
state: started
listen: Restart auditd

View file

@ -1,17 +1,27 @@
---
- name: Audit_Only | Create local Directories for hosts
when: fetch_audit_files
ansible.builtin.file:
mode: 'u+x,go-w'
path: "{{ audit_capture_files_dir }}/{{ inventory_hostname }}"
recurse: true
state: directory
delegate_to: localhost
become: false
- name: Audit_only | Fetch audit files
when:
- fetch_audit_output
- audit_only
ansible.builtin.import_tasks:
file: fetch_audit_output.yml
- name: Audit_only | Get audits from systems and put in group dir
when: fetch_audit_files
ansible.builtin.fetch:
dest: "{{ audit_capture_files_dir }}/{{ inventory_hostname }}/"
flat: true
mode: 'go-wx'
src: "{{ pre_audit_outfile }}"
- name: Audit_only | Show Audit Summary
when: audit_only
ansible.builtin.debug:
msg: "{{ audit_results.split('\n') }}"
- name: Audit_only | Stop task for host as audit_only selected
- name: Audit_only | Stop Playbook Audit Only selected
when: audit_only
ansible.builtin.meta: end_host
ansible.builtin.meta: end_play

View file

@ -7,7 +7,6 @@
- name: "POST | AUDITD | Set supported_syscalls variable"
ansible.builtin.shell: ausyscall --dump | awk '{print $2}'
changed_when: false
check_mode: false
failed_when: discovered_auditd_syscalls.rc not in [ 0, 1 ]
register: discovered_auditd_syscalls
@ -25,7 +24,7 @@
dest: /etc/audit/rules.d/99_auditd.rules
owner: root
group: root
mode: 'u-x,g-wx,o-rwx'
mode: 'u-x,go-wx'
diff: "{{ discovered_auditd_rules_file.stat.exists }}" # Only run diff if not a new file
register: discovered_auditd_rules_template_updated
notify:

View file

@ -1,47 +0,0 @@
---
# Stage to copy audit output to a centralised location
- name: "POST | FETCH | Fetch files and copy to controller"
when: audit_output_collection_method == "fetch"
ansible.builtin.fetch:
src: "{{ item }}"
dest: "{{ audit_output_destination }}"
flat: true
changed_when: true
failed_when: false
register: discovered_audit_fetch_state
loop:
- "{{ pre_audit_outfile }}"
- "{{ post_audit_outfile }}"
become: false
# Added this option for continuity but could be changed by adjusting the variable audit_conf_dest
# Allowing backup to one location
- name: "POST | FETCH | Copy files to location available to managed node"
when: audit_output_collection_method == "copy"
ansible.builtin.copy:
src: "{{ item }}"
dest: "{{ audit_output_destination }}"
mode: 'u-x,go-wx'
flat: true
failed_when: false
register: discovered_audit_copy_state
loop:
- "{{ pre_audit_outfile }}"
- "{{ post_audit_outfile }}"
- name: "POST | FETCH | Fetch files and copy to controller | Warning if issues with fetch_audit_files"
when:
- (audit_output_collection_method == "fetch" and not discovered_audit_fetch_state.changed) or
(audit_output_collection_method == "copy" and not discovered_audit_copy_state.changed)
block:
- name: "POST | FETCH | Fetch files and copy to controller | Warning if issues with fetch_audit_files"
ansible.builtin.debug:
msg: "Warning!! Unable to write to localhost {{ audit_output_destination }} for audit file copy"
- name: "POST | FETCH | Fetch files and copy to controller | Warning if issues with fetch_audit_files"
vars:
warn_control_id: "FETCH_AUDIT_FILES"
ansible.builtin.import_tasks:
file: warning_facts.yml

View file

@ -61,7 +61,7 @@
- crypto
- NIST800-53R5_SC-6
ansible.builtin.assert:
that: rhel9cis_additional_crypto_policy_module in rhel9cis_allowed_crypto_policies_modules
that: rhel9cis_crypto_policy_module in rhel9cis_allowed_crypto_policies_modules
fail_msg: "Crypto policy module is not a permitted version"
success_msg: "Crypto policy module is a permitted version"
@ -93,20 +93,18 @@
block:
- name: "Check password set for {{ ansible_env.SUDO_USER }} | Assert local password set" # noqa name[template]
ansible.builtin.assert:
that: |
(
((prelim_ansible_user_password_set.stdout | length != 0) and (prelim_ansible_user_password_set.stdout != "!!" ))
or
(ansible_env.SUDO_USER in rhel9cis_sudoers_exclude_nopasswd_list)
)
fail_msg: "You have {{ sudo_password_rule }} enabled but the user = {{ ansible_env.SUDO_USER }} has no password set or or the user is not included in the exception list for rule 5.2.4 - It can break access"
success_msg: "You have a password set for the {{ ansible_env.SUDO_USER }} user or the user is included in the exception list for rule 5.2.4"
that:
- prelim_ansible_user_password_set.stdout | length != 0
- prelim_ansible_user_password_set.stdout != "!!"
fail_msg: "You have {{ sudo_password_rule }} enabled but the user = {{ ansible_env.SUDO_USER }} has no password set - It can break access"
success_msg: "You have a password set for the {{ ansible_env.SUDO_USER }} user"
- name: "Check account is not locked for {{ ansible_env.SUDO_USER }} | Assert local account not locked" # noqa name[template]
ansible.builtin.assert:
that: (not prelim_ansible_user_password_set.stdout.startswith("!")) or (ansible_env.SUDO_USER in rhel9cis_sudoers_exclude_nopasswd_list)
that:
- not prelim_ansible_user_password_set.stdout.startswith("!")
fail_msg: "You have {{ sudo_password_rule }} enabled but the user = {{ ansible_env.SUDO_USER }} is locked - It can break access"
success_msg: "The local account {{ ansible_env.SUDO_USER }} is not locked or included in the exception list for rule 5.2.4"
success_msg: "The local account is not locked for {{ ansible_env.SUDO_USER }} user"
- name: "Check authselect profile is selected"
when: rhel9cis_allow_authselect_updates
@ -118,11 +116,17 @@
fail_msg: "You still have the default name for your authselect profile"
- name: "Check authselect profile is selected | Check current profile"
ansible.builtin.command: authselect list
ansible.builtin.shell: authselect current | head -1 | awk '{print $NF}'
changed_when: false
failed_when: prelim_authselect_current_profile.rc not in [ 0, 1 ]
register: prelim_authselect_current_profile
- name: "Check authselect profile is selected | Ensure profile name is set"
ansible.builtin.assert:
that: prelim_authselect_current_profile is defined
success_msg: "Authselect is running and profile is selected"
fail_msg: Authselect updates have been selected there are issues with profile selection"
- name: "Ensure root password is set"
when: rhel9cis_rule_5_4_2_4
tags:
@ -134,9 +138,8 @@
- rule_5.4.2.4
block:
- name: "Ensure root password is set"
ansible.builtin.shell: LC_ALL=C passwd -S root | grep -E "(Alternate authentication|Password set|Password locked)"
ansible.builtin.shell: passwd -S root | egrep -e "(Password set, SHA512 crypt|Password locked)"
changed_when: false
failed_when: prelim_root_passwd_set.rc not in [ 0, 1 ]
register: prelim_root_passwd_set
- name: "Ensure root password is set"
@ -212,46 +215,11 @@
- name: "Run post_remediation audit"
when: run_audit
tags: always
ansible.builtin.import_tasks:
file: post_remediation_audit.yml
- name: Add ansible file showing Benchmark and levels applied if audit details not present
when:
- create_benchmark_facts
- (post_audit_summary is defined) or
(ansible_local['compliance_facts']['lockdown_audit_details']['audit_summary'] is undefined and post_audit_summary is undefined)
tags:
- always
- benchmark
block:
- name: Create ansible facts directory if audit facts not present
ansible.builtin.file:
path: "{{ ansible_facts_path }}"
state: directory
owner: root
group: root
mode: 'u=rwx,go=rx'
- name: Create ansible facts file and levels applied if audit facts not present
ansible.builtin.template:
src: etc/ansible/compliance_facts.j2
dest: "{{ ansible_facts_path }}/compliance_facts.fact"
owner: root
group: root
mode: 'u-x,go=r'
- name: Fetch audit files
when:
- fetch_audit_output
- run_audit
tags: always
ansible.builtin.import_tasks:
file: fetch_audit_output.yml
- name: "Show Audit Summary"
when: run_audit
tags: always
ansible.builtin.debug:
msg: "{{ audit_results.split('\n') }}"

View file

@ -4,15 +4,15 @@
tags: always
block:
- name: "PRELIM | 5.5.2 | 6.2.7 | 6.2.8 | 6.2.20 | Parse /etc/passwd"
ansible.builtin.shell: cat /etc/passwd | grep -v '^#'
ansible.builtin.command: cat /etc/passwd
changed_when: false
check_mode: false
register: prelim_capture_passwd_file
register: prelim_passwd_file_audit
- name: "PRELIM | 5.4.2 | 7.2.8 | Split passwd entries"
- name: "PRELIM | 5.5.2 | 6.2.7 | 6.2.8 | 6.2.20 | Split passwd entries"
ansible.builtin.set_fact:
prelim_captured_passwd_data: "{{ prelim_capture_passwd_file.stdout_lines | map('regex_replace', ld_passwd_regex, ld_passwd_yaml) | map('from_yaml') | list }}"
loop: "{{ prelim_capture_passwd_file.stdout_lines }}"
rhel9cis_passwd: "{{ prelim_passwd_file_audit.stdout_lines | map('regex_replace', ld_passwd_regex, ld_passwd_yaml) | map('from_yaml') | list }}"
loop: "{{ prelim_passwd_file_audit.stdout_lines }}"
vars:
ld_passwd_regex: >-
^(?P<id>[^:]*):(?P<password>[^:]*):(?P<uid>[^:]*):(?P<gid>[^:]*):(?P<gecos>[^:]*):(?P<dir>[^:]*):(?P<shell>[^:]*)

View file

@ -1,13 +1,22 @@
---
- name: Post Audit | Run post_remediation {{ benchmark }} audit # noqa name[template]
ansible.builtin.shell: "umask 0022 && {{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -m {{ audit_max_concurrent }} -o {{ post_audit_outfile }} -g \"{{ group_names }}\"" # noqa yaml[line-length]
ansible.builtin.command: "{{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -o {{ post_audit_outfile }} -g \"{{ group_names }}\""
changed_when: true
environment:
AUDIT_BIN: "{{ audit_bin }}"
AUDIT_CONTENT_LOCATION: "{{ audit_conf_dest | default('/opt') }}"
AUDIT_FILE: goss.yml
- name: Post Audit | ensure audit files readable by users
ansible.builtin.file:
path: "{{ item }}"
mode: '0644'
state: file
loop:
- "{{ post_audit_outfile }}"
- "{{ pre_audit_outfile }}"
- name: Post Audit | Capture audit data if json format
when: audit_format == "json"
block:
@ -24,7 +33,7 @@
when: audit_format == "documentation"
block:
- name: Post Audit | Capture audit data if documentation format
ansible.builtin.shell: tail -2 "{{ post_audit_outfile }}" | tac | tr '\n' ' '
ansible.builtin.shell: tail -2 "{{ pre_audit_outfile }}" | tac | tr '\n' ' '
changed_when: false
register: post_audit_summary

View file

@ -1,5 +1,4 @@
---
- name: Pre Audit Setup | Setup the LE audit
when: setup_audit
tags: setup_audit
@ -58,7 +57,6 @@
- name: Pre Audit Setup | If audit ensure goss is available
when: not prelim_goss_available.stat.exists
ansible.builtin.assert:
that: prelim_goss_available['stat']['exists'] == true
msg: "Audit has been selected: unable to find goss binary at {{ audit_bin }}"
- name: Pre Audit Setup | Copy ansible default vars values to test audit
@ -72,7 +70,7 @@
mode: 'go-rwx'
- name: Pre Audit | Run pre_remediation audit {{ benchmark }} # noqa name[template]
ansible.builtin.shell: "umask 0022 && {{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -m {{ audit_max_concurrent }} -o {{ pre_audit_outfile }} -g \"{{ group_names }}\"" # noqa yaml[line-length]
ansible.builtin.command: "{{ audit_conf_dir }}/run_audit.sh -v {{ audit_vars_path }} -f {{ audit_format }} -o {{ pre_audit_outfile }} -g \"{{ group_names }}\"" # noqa yaml[line-length]
changed_when: true
environment:
AUDIT_BIN: "{{ audit_bin }}"
@ -85,7 +83,6 @@
- name: Pre Audit | Capture audit data if json format
ansible.builtin.shell: grep -E '\"summary-line.*Count:.*Failed' "{{ pre_audit_outfile }}" | cut -d'"' -f4
changed_when: false
failed_when: pre_audit_summary.stderr | length > 0
register: pre_audit_summary
- name: Pre Audit | Set Fact for audit summary
@ -98,7 +95,6 @@
- name: Pre Audit | Capture audit data if documentation format
ansible.builtin.shell: tail -2 "{{ pre_audit_outfile }}" | tac | tr '\n' ' '
changed_when: false
failed_when: pre_audit_summary.stderr | length > 0
register: pre_audit_summary
- name: Pre Audit | Set Fact for audit summary

View file

@ -4,7 +4,9 @@
# List users in order to look files inside each home directory
- name: "PRELIM | Include audit specific variables"
when: run_audit or audit_only or setup_audit
when:
- run_audit or audit_only
- setup_audit
tags:
- setup_audit
- run_audit
@ -12,30 +14,24 @@
file: audit.yml
- name: "PRELIM | Include pre-remediation audit tasks"
when: run_audit or audit_only or setup_audit
when:
- run_audit or audit_only
- setup_audit
tags: run_audit
ansible.builtin.import_tasks: pre_remediation_audit.yml
- name: "PRELIM | AUDIT | Interactive Users"
tags: always
ansible.builtin.shell: >
grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false" && $7 != "/dev/null") { print $1":"$3":"$6 }'
grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false" && $7 != "/dev/null") { print $1 }'
changed_when: false
check_mode: false
register: prelim_interactive_users_raw
- name: "PRELIM | AUDIT | Interactive Users (reformat)"
tags: always
ansible.builtin.set_fact:
prelim_interactive_users: "{{ prelim_interactive_users | default([]) + [dict([('username', item.split(':')[0]), ('uid', item.split(':')[1]), ('home', item.split(':')[2])])] }}"
loop: "{{ prelim_interactive_users_raw.stdout_lines }}"
register: prelim_interactive_usernames
- name: "PRELIM | AUDIT | Interactive User accounts home directories"
tags: always
ansible.builtin.shell: >
grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false" && $7 != "/dev/null") { print $6 }'
grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false") { print $6 }'
changed_when: false
check_mode: false
register: prelim_interactive_users_home
- name: "PRELIM | AUDIT | Interactive UIDs"
@ -43,7 +39,6 @@
ansible.builtin.shell: >
grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false") { print $3 }'
changed_when: false
check_mode: false
register: prelim_interactive_uids
- name: "PRELIM | AUDIT | Capture /etc/password variables"
@ -69,7 +64,6 @@
ansible.builtin.shell: |
mount | awk '{print $1, $3, $5, $6}'
changed_when: false
check_mode: false
register: prelim_mount_output
- name: PRELIM | AUDIT | Section 1.1 | Retrieve mount options - build fact # This is inherited and used in mountpoints tasks
@ -106,7 +100,6 @@
ansible.builtin.command: rpm -q gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SUMMARY}\n' # noqa command-instead-of-module
changed_when: false
failed_when: false
check_mode: false
register: prelim_check_gpg_imported
- name: "PRELIM | AUDIT | Import gpg keys | Check Package" # noqa command-instead-of-module
@ -114,7 +107,6 @@
ansible.builtin.shell: rpm -qi redhat-release | grep Signature # noqa command-instead-of-module
changed_when: false
failed_when: false
check_mode: false
register: prelim_os_gpg_package_valid
- name: "PRELIM | PATCH | Force keys to be imported" # noqa command-instead-of-module
@ -137,7 +129,8 @@
register: prelim_systemd_coredump
- name: "PRELIM | PATCH | Setup crypto-policy"
when: rhel9cis_crypto_policy_ansiblemanaged
when:
- rhel9cis_rule_1_6_1
tags:
- level1-server
- level1-workstation
@ -167,7 +160,6 @@
current_crypto_module: "{{ prelim_system_wide_crypto_policy.stdout.split(':')[1] }}"
- name: "PRELIM | AUDIT | Set facts based on boot type"
tags: always
block:
- name: "PRELIM | AUDIT | Check whether machine is UEFI-based"
ansible.builtin.stat:
@ -186,14 +178,17 @@
grub2_path: /etc/grub2-efi.cfg
- name: "PRELIM | AUDIT | Discover Gnome Desktop Environment"
tags: always
tags:
- always
ansible.builtin.stat:
path: /usr/share/gnome/gnome-version.xml
register: prelim_gnome_present
- name: "PRELIM | PATCH | Install dconf if gui installed"
when: rhel9cis_gui
tags: always
when:
- rhel9cis_gui
tags:
- always
ansible.builtin.package:
name: dconf
state: present
@ -202,13 +197,13 @@
when:
- rhel9cis_rule_3_1_2
- not system_is_container
tags: always
tags:
- always
block:
- name: "PRELIM | AUDIT | Discover is wireless adapter on system"
- name: "PRELIM | AUDIT | Discover is wirelss adapter on system"
ansible.builtin.command: find /sys/class/net/*/ -type d -name wireless
register: discover_wireless_adapters
changed_when: false
check_mode: false
failed_when: discover_wireless_adapters.rc not in [ 0, 1 ]
- name: "PRELIM | PATCH | Install Network-Manager | if wireless adapter present"
@ -248,12 +243,6 @@
mode: 'go-rwx'
state: touch
- name: "PRELIM | PATCH | sshd_config.d/50-redhat.conf exists"
when: rhel9cis_rule_5_1_10 or rhel9cis_rule_5_1_11
ansible.builtin.stat:
path: /etc/ssh/sshd_config.d/50-redhat.conf
register: prelim_sshd_50_redhat_file
- name: "PRELIM | AUDIT | Capture pam security related files"
tags: always
ansible.builtin.find:
@ -309,7 +298,6 @@
tags: always
ansible.builtin.shell: grep ^log_file /etc/audit/auditd.conf | awk '{ print $NF }'
changed_when: false
check_mode: false
register: prelim_auditd_logfile
- name: "PRELIM | AUDIT | Audit conf and rules files | list files"
@ -332,31 +320,27 @@
patterns: '*.conf,*.rules'
register: prelim_auditd_conf_files
- name: "PRELIM | AUDIT | Discover Interactive UID_MIN and UID_MAX from /etc/login.defs"
- name: "PRELIM | AUDIT | Discover Interactive UID MIN and MIN from logins.def"
when: rhel9cis_discover_int_uid
tags: always
block:
- name: "PRELIM | AUDIT | Capture UID_MIN from /etc/login.defs"
ansible.builtin.command: awk '/^UID_MIN/ {print $2}' /etc/login.defs
- name: "PRELIM | AUDIT | Capture UID_MIN information from logins.def"
ansible.builtin.shell: grep -w "^UID_MIN" /etc/login.defs | awk '{print $NF}'
changed_when: false
failed_when: false
check_mode: false
register: prelim_uid_min_id
- name: "PRELIM | AUDIT | Capture UID_MAX from /etc/login.defs"
ansible.builtin.command: awk '/^UID_MAX/ {print $2}' /etc/login.defs
- name: "PRELIM | AUDIT | Capture UID_MAX information from logins.def"
ansible.builtin.shell: grep -w "^UID_MAX" /etc/login.defs | awk '{print $NF}'
changed_when: false
failed_when: false
check_mode: false
register: prelim_uid_max_id
- name: "PRELIM | AUDIT | Set facts for interactive UID/GID ranges"
tags: always
ansible.builtin.set_fact:
prelim_min_int_uid: "{{ prelim_uid_min_id.stdout | default(min_int_uid) }}"
prelim_max_int_uid: "{{ prelim_uid_max_id.stdout | default(max_int_uid) }}"
- name: "PRELIM | AUDIT | Set Fact for interactive uid/gid"
ansible.builtin.set_fact:
prelim_min_int_uid: "{{ prelim_uid_min_id.stdout }}"
prelim_max_int_uid: "{{ prelim_uid_max_id.stdout }}"
- name: "PRELIM | AUDIT | Gather the package facts after prelim"
tags: always
tags:
- always
ansible.builtin.package_facts:
manager: auto

View file

@ -21,12 +21,12 @@
register: discovered_home_mount
- name: "1.1.2.3.1 | AUDIT | Ensure /home is a separate partition | Absent"
when: discovered_home_mount is undefined
when: discovered_dev_shm_mount is undefined
ansible.builtin.debug:
msg: "Warning!! {{ required_mount }} is not mounted on a separate partition"
- name: "1.1.2.3.1 | AUDIT | Ensure /home is a separate partition | Present"
when: discovered_home_mount is undefined
when: discovered_dev_shm_mount is undefined
ansible.builtin.import_tasks:
file: warning_facts.yml

View file

@ -22,12 +22,12 @@
register: discovered_var_mount
- name: "1.1.2.4.1 | AUDIT | Ensure /var is a separate partition | Absent"
when: discovered_var_mount is undefined
when: discovered_dev_shm_mount is undefined
ansible.builtin.debug:
msg: "Warning!! {{ required_mount }} is not mounted on a separate partition"
- name: "1.1.2.4.1 | AUDIT | Ensure /var is a separate partition | Present"
when: discovered_var_mount is undefined
when: discovered_dev_shm_mount is undefined
ansible.builtin.import_tasks:
file: warning_facts.yml

View file

@ -1,6 +1,6 @@
---
- name: "1.1.2.6.1 | PATCH | Ensure /var/log is a separate partition"
- name: "1/.1 | PATCH | Ensure /var/log is a separate partition"
when:
- rhel9cis_rule_1_1_2_6_1
- required_mount not in prelim_mount_names

View file

@ -1,6 +1,6 @@
---
- name: "1.1.2.7.1 | PATCH | Ensure /var/log/audit is a separate partition"
- name: "1/.1 | PATCH | Ensure /var/log/audit is a separate partition"
when:
- rhel9cis_rule_1_1_2_7_1
- required_mount not in prelim_mount_names

View file

@ -106,7 +106,7 @@
warn_control_id: '1.3.1.6'
block:
- name: "1.3.1.6 | AUDIT | Ensure no unconfined services exist | Find the unconfined services"
ansible.builtin.shell: ps -eZ | grep unconfined_service_t | grep -Evw "tr|ps|egrep|bash|awk" | tr ':' ' ' | awk '{ print $NF }'
ansible.builtin.shell: ps -eZ | grep unconfined_service_t | egrep -vw "tr|ps|egrep|bash|awk" | tr ':' ' ' | awk '{ print $NF }'
register: discovered_unconf_services
failed_when: false
changed_when: false

View file

@ -29,8 +29,7 @@
- rule_1.4.2
- NIST800-53R5_AC-3
block:
- name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | bios based system"
when: rhel9cis_legacy_boot
- name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured"
ansible.builtin.file:
path: "/boot/grub2/{{ item.path }}"
owner: root
@ -40,32 +39,6 @@
modification_time: preserve
access_time: preserve
loop:
- { path: 'grub.cfg', mode: 'u-x,go-rwx' }
- { path: 'grubenv', mode: 'u-x,go-rwx' }
- { path: 'user.cfg', mode: 'u-x,go-rwx' }
- name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | efi based system"
when: not rhel9cis_legacy_boot
vars:
efi_mount_options: ['umask=0077', 'fmask=0077', 'uid=0', 'gid=0']
block:
- name: "1.4.2 | AUDIT | Ensure permissions on bootloader config are configured | efi based system | capture current state"
ansible.builtin.shell: grep "^[^#;]" /etc/fstab | grep '/boot/efi' | awk -F" " '{print $4}'
changed_when: false
check_mode: false
register: discovered_efi_fstab
- name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | efi based system | Build Options"
when: item not in discovered_efi_fstab.stdout
ansible.builtin.set_fact:
efi_mount_opts_addition: "{{ efi_mount_opts_addition + ',' + item }}"
loop: "{{ efi_mount_options }}"
- name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | efi based system | Add mount options"
when: efi_mount_opts_addition | length > 0
ansible.builtin.lineinfile:
path: /etc/fstab
regexp: (.*/boot/efi\s*\w*\s*){{ discovered_efi_fstab.stdout }}(.*)
line: \1{{ discovered_efi_fstab.stdout + efi_mount_opts_addition }}\2
backrefs: true
notify: Remount /boot/efi
- { path: 'grub.cfg', mode: '0700' }
- { path: 'grubenv', mode: 'go-rwx' }
- { path: 'user.cfg', mode: 'go-rwx' }

View file

@ -1,9 +1,7 @@
---
- name: "1.6.1 | AUDIT | Ensure system-wide crypto policy is not legacy"
when:
- rhel9cis_rule_1_6_1
- rhel9cis_crypto_policy_ansiblemanaged
when: rhel9cis_rule_1_6_1
tags:
- level1-server
- level1-workstation
@ -23,14 +21,12 @@
tags:
- level1-server
- level1-workstation
- sshd
- automated
- patch
- rule_1.6.2
- NIST800-53R5_SC-8
- NIST800-53R5_IA-5
- NIST800-53R5_AC-17
- NIST800-53R5_SC-6
- NIST800-53R5_AC-17- NIST800-53R5_SC-6
ansible.builtin.lineinfile:
path: /etc/sysconfig/sshd
regexp: ^CRYPTO_POLICY\s*=
@ -41,7 +37,6 @@
when:
- rhel9cis_rule_1_6_3
- "'NO-SHA1' not in rhel9cis_crypto_policy_module"
- rhel9cis_crypto_policy_ansiblemanaged
tags:
- level1-server
- level1-workstation
@ -72,7 +67,6 @@
when:
- rhel9cis_rule_1_6_4
- "'NO-WEAKMAC' not in rhel9cis_crypto_policy_module"
- rhel9cis_crypto_policy_ansiblemanaged
tags:
- level1-server
- level1-workstation
@ -82,6 +76,7 @@
- rule_1.6.4
- NIST800-53R5_SC-6
block:
- name: "1.6.4 | PATCH | Ensure system wide crypto policy disables macs less than 128 bits | Add submodule exclusion"
ansible.builtin.template:
src: etc/crypto-policies/policies/modules/NO-WEAKMAC.pmod.j2
@ -103,7 +98,6 @@
when:
- rhel9cis_rule_1_6_5
- "'NO-SSHCBC' not in rhel9cis_crypto_policy_module"
- rhel9cis_crypto_policy_ansiblemanaged
tags:
- level1-server
- level1-workstation
@ -134,7 +128,6 @@
when:
- rhel9cis_rule_1_6_6
- "'NO-SSHWEAKCIPHERS' not in rhel9cis_crypto_policy_module"
- rhel9cis_crypto_policy_ansiblemanaged
tags:
- level1-server
- level1-workstation
@ -165,7 +158,6 @@
when:
- rhel9cis_rule_1_6_7
- "'NO-SSHETM' not in rhel9cis_crypto_policy_module"
- rhel9cis_crypto_policy_ansiblemanaged
tags:
- level1-server
- level1-workstation

View file

@ -41,7 +41,7 @@
file: cis_1.2.2.x.yml
- name: "SECTION | 1.3.1 | Configure SELinux"
ansible.builtin.import_tasks:
ansible.builtin.include_tasks:
file: cis_1.3.1.x.yml
- name: "SECTION | 1.4 | Configure Bootloader"
@ -61,6 +61,5 @@
file: cis_1.7.x.yml
- name: "SECTION | 1.8 | Gnome Display Manager"
when: rhel9cis_display_manager == 'gdm'
ansible.builtin.import_tasks:
file: cis_1.8.x.yml

View file

@ -25,7 +25,7 @@
when:
- not rhel9cis_autofs_services
- rhel9cis_autofs_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: autofs
enabled: false
@ -57,7 +57,7 @@
when:
- not rhel9cis_avahi_server
- rhel9cis_avahi_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -90,7 +90,7 @@
when:
- not rhel9cis_dhcp_server
- rhel9cis_dhcp_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -123,7 +123,7 @@
when:
- not rhel9cis_dns_server
- rhel9cis_dns_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: named.service
enabled: false
@ -153,7 +153,7 @@
when:
- not rhel9cis_dnsmasq_server
- rhel9cis_dnsmasq_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: dnsmasq.service
enabled: false
@ -184,7 +184,7 @@
when:
- not rhel9cis_samba_server
- rhel9cis_samba_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: smb.service
enabled: false
@ -215,7 +215,7 @@
when:
- not rhel9cis_ftp_server
- rhel9cis_ftp_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: vsftpd.service
enabled: false
@ -249,7 +249,7 @@
when:
- not rhel9cis_message_server
- rhel9cis_message_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -285,7 +285,7 @@
when:
- not rhel9cis_nfs_server
- rhel9cis_nfs_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: nfs-server.service
enabled: false
@ -302,7 +302,7 @@
- nis
- NIST800-53R5_CM-7
- rule_2.1.10
notify: Systemd daemon reload
notify: Systemd_daemon_reload
block:
- name: "2.1.10 | PATCH | Ensure nis server services are not in use | Remove package"
when:
@ -344,7 +344,7 @@
when:
- not rhel9cis_print_server
- rhel9cis_print_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -378,7 +378,7 @@
when:
- not rhel9cis_rpc_server
- rhel9cis_rpc_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -412,7 +412,7 @@
when:
- not rhel9cis_rsync_server
- rhel9cis_rsync_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -445,7 +445,7 @@
when:
- not rhel9cis_snmp_server
- rhel9cis_snmp_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: snmpd.service
enabled: false
@ -476,7 +476,7 @@
when:
- not rhel9cis_telnet_server
- rhel9cis_telnet_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: telnet.socket
enabled: false
@ -506,7 +506,7 @@
when:
- not rhel9cis_tftp_server
- rhel9cis_tftp_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -540,7 +540,7 @@
when:
- not rhel9cis_squid_server
- rhel9cis_squid_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: squid.service
enabled: false
@ -580,7 +580,7 @@
when:
- not rhel9cis_httpd_server
- rhel9cis_httpd_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: httpd.service
enabled: false
@ -591,7 +591,7 @@
when:
- not rhel9cis_nginx_server
- rhel9cis_nginx_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: ngnix.service
enabled: false
@ -621,7 +621,7 @@
when:
- not rhel9cis_xinetd_server
- rhel9cis_xinetd_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: xinetd.service
enabled: false
@ -657,7 +657,7 @@
- postfix
- NIST800-53R5_CM-7
- rule_2.1.21
notify: Restart postfix
notify: Restart_postfix
ansible.builtin.lineinfile:
path: /etc/postfix/main.cf
regexp: "^(#)?inet_interfaces"

View file

@ -16,30 +16,15 @@
- rule_3.1.1
- NIST800-53R5_CM-7
block:
- name: "3.1.1 | PATCH | Ensure IPv6 status is identified | Set vars for sysctl template"
when: "'sysctl' in rhel9cis_ipv6_disable_method"
- name: "3.1.1 | PATCH | Ensure IPv6 status is identified | refresh"
ansible.builtin.set_fact:
rhel9cis_sysctl_update: true
rhel9cis_flush_ipv6_route: true
- name: "3.1.1 | AUDIT | Ensure IPv6 status is identified | Message out implementation info"
when: "'sysctl' in rhel9cis_ipv6_disable_method"
- name: "3.1.1 | PATCH | Ensure IPv6 status is identified | disable"
ansible.builtin.debug:
msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-disable_ipv6.conf"
- name: "3.1.1 | AUDIT | Ensure IPv6 status is identified | Find IPv6 status"
when: "'kernel' in rhel9cis_ipv6_disable_method"
ansible.builtin.command: grubby --info=ALL
changed_when: false
failed_when: false
register: discovered_rhel9cis_3_1_1_ipv6_status
- name: "3.1.1 | PATCH | Ensure IPv6 status is identified | Disable IPV6 via Kernel"
when:
- "'kernel' in rhel9cis_ipv6_disable_method"
- "'ipv6.disable=1' not in discovered_rhel9cis_3_1_1_ipv6_status.stdout"
ansible.builtin.shell: grubby --update-kernel=ALL --args="ipv6.disable=1"
- name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled"
when:
- rhel9cis_rule_3_1_2
@ -54,7 +39,7 @@
warn_control_id: '3.1.2'
block:
- name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Check for network-manager tool"
when: "rhel9cis_network_manager_package_name in ansible_facts.packages"
when: "'network-manager' in ansible_facts.packages"
ansible.builtin.command: nmcli radio wifi
changed_when: false
failed_when: false
@ -63,19 +48,19 @@
- name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Disable wireless if network-manager installed"
when:
- "rhel9cis_network_manager_package_name in ansible_facts.packages"
- "'network-manager' in ansible_facts.packages"
- "'enabled' in discovered_wifi_status.stdout"
ansible.builtin.command: nmcli radio all off
changed_when: discovered_nmcli_radio_off.rc == 0
register: discovered_nmcli_radio_off
- name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Warn about wireless if network-manager not installed"
when: "rhel9cis_network_manager_package_name not in ansible_facts.packages"
when: "'network-manager' not in ansible_facts.packages"
ansible.builtin.debug:
msg: "Warning!! You need to disable wireless interfaces manually since network-manager is not installed"
- name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Set warning count"
when: "rhel9cis_network_manager_package_name not in ansible_facts.packages"
when: "'network-manager' not in ansible_facts.packages"
ansible.builtin.import_tasks:
file: warning_facts.yml
@ -101,7 +86,7 @@
when:
- not rhel9cis_bluetooth_service
- rhel9cis_bluetooth_mask
notify: Systemd daemon reload
notify: Systemd_daemon_reload
ansible.builtin.systemd:
name: bluetooth.service
enabled: false

View file

@ -25,8 +25,8 @@
- name: "3.2.1 | PATCH | Ensure dccp kernel module is not available | blacklist"
ansible.builtin.lineinfile:
path: /etc/modprobe.d/blacklist.conf
regexp: "^(#)?blacklist dccp(\\s|$)"
line: "blacklist dccp"
regexp: "^(#)?blacklist cramfs(\\s|$)"
line: "blacklist cramfs"
create: true
mode: 'u-x,go-rwx'

View file

@ -240,12 +240,12 @@
- rule_3.3.9
- NIST800-53R5_AU-3
block:
- name: "3.3.9 | PATCH | Ensure suspicious packets are logged | Set Fact"
- name: "3.3.4 | PATCH | Ensure suspicious packets are logged | Set Fact"
ansible.builtin.set_fact:
rhel9cis_sysctl_update: true
rhel9cis_flush_ipv4_route: true
- name: "3.3.9 | PATCH | Ensure suspicious packets are logged"
- name: "3.3.4 | PATCH | Ensure suspicious packets are logged"
ansible.builtin.debug:
msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/60-netipv4_sysctl.conf"

View file

@ -81,7 +81,7 @@
register: discovered_nftables_inconnectionrule
- name: "4.3.2 | AUDIT | Ensure nftables established connections are configured | Gather outbound connection rules"
ansible.builtin.shell: nft list ruleset | awk '/hook output/,/}/' | grep -E 'ip protocol (tcp|udp|icmp) ct state'
ansible.builtin.command: nft list ruleset | awk '/hook output/,/}/' | grep -E 'ip protocol (tcp|udp|icmp) ct state'
changed_when: false
failed_when: false
register: discovered_nftables_outconnectionrule

View file

@ -6,7 +6,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- permissions
- rule_5.1.1
- NIST800-53R5_AC-3
@ -23,7 +23,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- permissions
- rule_5.1.2
- NIST800-53R5_AC-3
@ -41,8 +41,8 @@
ansible.builtin.file:
path: "{{ item.path }}"
owner: root
group: "{{ 'ssh_keys' if (item.gr_name == 'ssh_keys') else 'root' }}"
mode: "{{ 'u-x,g-wx,o-rwx' if (item.gr_name == 'ssh_keys') else 'u-x,go-rwx' }}"
group: root
mode: 'u-x,go-rwx'
loop: "{{ discovered_ssh_private_host_key.files }}"
loop_control:
label: "{{ item.path }}"
@ -53,7 +53,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.3
- NIST800-53R5_AC-3
- NIST800-53R5_MP-2
@ -80,7 +80,6 @@
when:
- rhel9cis_rule_5_1_4
- "'NO-SSHWEAKCIPHERS' not in rhel9cis_crypto_policy_module"
- rhel9cis_crypto_policy_ansiblemanaged
tags:
- level1-server
- level1-workstation
@ -109,7 +108,6 @@
when:
- rhel9cis_rule_5_1_5
- "'NO-SHA1' not in rhel9cis_crypto_policy_module"
- rhel9cis_crypto_policy_ansiblemanaged
tags:
- level1-server
- level1-workstation
@ -138,7 +136,6 @@
when:
- rhel9cis_rule_5_1_6
- "'NO-SSHWEAKMACS' not in rhel9cis_crypto_policy_module"
- rhel9cis_crypto_policy_ansiblemanaged
tags:
- level1-server
- level1-workstation
@ -169,7 +166,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.7
- NIST800-53R5_AC-3
- NIST800-53R5_MP-2
@ -198,8 +195,6 @@
path: "{{ rhel9cis_sshd_config_file }}"
regexp: "^DenyUsers"
line: "DenyUsers {{ rhel9cis_sshd_denyusers }}"
insertbefore: "^Match"
firstmatch: true
validate: sshd -t -f %s
notify: Restart sshd
@ -218,7 +213,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.8
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -236,7 +231,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.9
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -266,7 +261,7 @@
- level2-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.10
- NIST800-53R5_CM-7
block:
@ -279,10 +274,9 @@
notify: Restart sshd
- name: "5.1.10 | PATCH | Ensure sshd DisableForwarding is enabled | override"
when: prelim_sshd_50_redhat_file.stat.exists
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config.d/50-redhat.conf
regexp: (?i)^(#|)\s*X11Forwarding
regexp: ^(?i)(#|)\s*X11Forwarding
line: 'X11Forwarding {{ rhel9cis_sshd_x11forwarding }}'
validate: sshd -t -f %s
notify: Restart sshd
@ -293,7 +287,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- sshs
- rule_5.1.11
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -302,10 +296,9 @@
- NIST800-53R5_IA-5
block:
- name: "5.1.11 | PATCH | Ensure sshd GSSAPIAuthentication is disabled | redhat file"
when: prelim_sshd_50_redhat_file.stat.exists
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config.d/50-redhat.conf
regexp: (?i)^(#|)\s*GSSAPIAuthentication
regexp: ^(?i)(#|)\s*GSSAPIAuthentication
line: GSSAPIAuthentication no
validate: sshd -t -f %s
notify: Restart sshd
@ -313,7 +306,7 @@
- name: "5.1.11 | PATCH | Ensure sshd GSSAPIAuthentication is disabled | ssh config"
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: (?i)^(#|)\s*GSSAPIAuthentication
regexp: ^(?i)(#|)\s*GSSAPIAuthentication
line: GSSAPIAuthentication no
validate: sshd -t -f %s
notify: Restart sshd
@ -324,7 +317,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.12
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -333,7 +326,7 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: (?i)^(#|)\s*HostbasedAuthentication
regexp: ^(?i)(#|)\s*HostbasedAuthentication
line: 'HostbasedAuthentication no'
validate: sshd -t -f %s
notify: Restart sshd
@ -344,7 +337,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.13
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -353,10 +346,8 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: (?i)^(#|)\s*IgnoreRhosts
regexp: ^(?i)(#|)\s*IgnoreRhosts
line: 'IgnoreRhosts yes'
insertbefore: "^Match"
firstmatch: true
validate: sshd -t -f %s
notify: Restart sshd
@ -366,15 +357,13 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.14
- NIST800-53R5_CM-6
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: (?i)^(#|)\s*LoginGraceTime
regexp: ^(?i)(#|)\s*LoginGraceTime
line: "LoginGraceTime {{ rhel9cis_sshd_logingracetime }}"
insertbefore: "^Match"
firstmatch: true
validate: sshd -t -f %s
notify: Restart sshd
@ -384,17 +373,15 @@
- level1-server
- level1-workstation
- patch
- sshd
- sshs
- rule_5.1.15
- NIST800-53R5_AU-3
- NIST800-53R5_AU-12
- NIST800-53R5_SI-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: (?i)^(#|)\s*LogLevel
regexp: ^(?i)(#|)\s*LogLevel
line: 'LogLevel {{ rhel9cis_ssh_loglevel }}'
insertbefore: "^Match"
firstmatch: true
validate: sshd -t -f %s
notify: Restart sshd
@ -404,7 +391,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.16
- NIST800-53R5_AU-3
ansible.builtin.lineinfile:
@ -420,7 +407,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.17
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -429,7 +416,7 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: (?i)^(#|)\s*MaxStartups
regexp: ^(?i)(#|)\s*MaxStartups
line: 'MaxStartups {{ rhel9cis_ssh_maxstartups }}'
validate: sshd -t -f %s
notify: Restart sshd
@ -440,7 +427,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.18
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -449,7 +436,7 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: (?i)^(#|)\s*MaxSessions
regexp: ^(?i)(#|)\s*MaxSessions
line: 'MaxSessions {{ rhel9cis_ssh_maxsessions }}'
validate: sshd -t -f %s
notify: Restart sshd
@ -460,7 +447,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.19
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -469,7 +456,7 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: (?i)^(#|)\s*PermitEmptyPasswords
regexp: ^(?i)(#|)\s*PermitEmptyPasswords
line: 'PermitEmptyPasswords no'
validate: sshd -t -f %s
notify: Restart sshd
@ -480,14 +467,14 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.20
- NIST800-53R5_AC-6
block:
- name: "5.1.20 | PATCH | Ensure sshd PermitRootLogin is disabled | config file"
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: (?i)^(#|)\s*PermitRootLogin
regexp: ^(?i)(#|)\s*PermitRootLogin
line: 'PermitRootLogin no'
validate: sshd -t -f %s
notify: Restart sshd
@ -504,7 +491,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.21
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -513,7 +500,7 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: (?i)^(#|)\s*PermitUserEnvironment
regexp: ^(?i)(#|)\s*PermitUserEnvironment
line: 'PermitUserEnvironment no'
validate: sshd -t -f %s
notify: Restart sshd
@ -524,7 +511,7 @@
- level1-server
- level1-workstation
- patch
- sshd
- ssh
- rule_5.1.22
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -533,7 +520,7 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: (?i)^(#|)\s*UsePAM
regexp: ^(?i)(#|)\s*UsePAM
line: 'UsePAM yes'
validate: sshd -t -f %s
notify: Restart sshd

View file

@ -14,7 +14,9 @@
- rule_5.3.2.1
block:
- name: "5.3.2.1 | PATCH | Ensure active authselect profile includes pam modules | Create custom profiles"
when: rhel9cis_authselect_custom_profile_name not in prelim_authselect_current_profile.stdout
when:
- rhel9cis_authselect_custom_profile_name not in prelim_authselect_current_profile.stdout or
prelim_authselect_current_profile.stdout is not defined
ansible.builtin.command: "/usr/bin/authselect create-profile {{ rhel9cis_authselect_custom_profile_name }} -b {{ rhel9cis_authselect_default_profile_to_copy }}"
changed_when: false
args:
@ -91,15 +93,9 @@
insertafter: "{{ item.after | default(omit) }}"
line: "{{ item.line }}"
loop:
- regexp: "auth\\s+required\\s+pam_faillock.so\\s+preauth"
after: "auth\\s+required\\s+pam_env.so" # yamllint disable-line rule:colons
line: "auth required pam_faillock.so preauth silent deny=3 unlock_timeout={{ rhel9cis_pam_faillock_unlock_time }}" # yamllint disable-line rule:colons
- regexp: "auth\\s+required\\s+pam_faillock.so\\s+authfail"
before: "auth\\s+required\\s+pam_deny.so"
line: "auth required pam_faillock.so authfail silent deny=3 unlock_timeout={{ rhel9cis_pam_faillock_unlock_time }}" # yamllint disable-line rule:colons
- regexp: "account\\s+required\\s+pam_faillock.so"
before: "account\\s+required\\s+pam_unix.so"
line: "account required pam_faillock.so" # yamllint disable-line rule:colons
- { regexp: auth\s*required\s*pam_faillock.so preauth, after: auth\s*required\s*pam_env.so, line: "auth required pam_faillock.so preauth silent deny=3 unlock_timeout={{ rhel9cis_pam_faillock_unlock_time }}" }
- { regexp: auth\s*required\s*pam_faillock.so authfail, before: auth\s*required\s*pam_deny.so, line: "auth required pam_faillock.so authfail silent deny=3 unlock_timeout={{ rhel9cis_pam_faillock_unlock_time }}" }
- { regexp: account\s*required\s*pam_faillock.so, before: account\s*required\s*pam_unix.so, line: "account required pam_faillock.so" }
- name: "5.3.2.2 | AUDIT | Ensure pam_faillock module is enabled | Add lines password-auth"
when: not rhel9cis_allow_authselect_updates
@ -110,15 +106,9 @@
insertafter: "{{ item.after | default(omit) }}"
line: "{{ item.line }}"
loop:
- regexp: "auth\\s+required\\s+pam_faillock.so\\s+preauth"
after: "auth\\s+required\\s+pam_env.so" # yamllint disable-line rule:colons
line: "auth required pam_faillock.so preauth silent deny=3 unlock_timeout={{ rhel9cis_pam_faillock_unlock_time }}" # yamllint disable-line rule:colons
- regexp: "auth\\s+required\\s+pam_faillock.so\\s+authfail"
before: "auth\\s+required\\s+pam_deny.so"
line: "auth required pam_faillock.so authfail silent deny=3 unlock_timeout={{ rhel9cis_pam_faillock_unlock_time }}" # yamllint disable-line rule:colons
- regexp: "account\\s+required\\s+pam_faillock.so"
before: "account\\s+required\\s+pam_unix.so"
line: "account required pam_faillock.so" # yamllint disable-line rule:colons
- { regexp: auth\s*required\s*pam_faillock.so preauth, after: auth\s*required\s*pam_env.so, line: "auth required pam_faillock.so preauth silent deny=3 unlock_timeout={{ rhel9cis_pam_faillock_unlock_time }}" }
- { regexp: auth\s*required\s*pam_faillock.so authfail, before: auth\s*required\s*pam_deny.so, line: "auth required pam_faillock.so authfail silent deny=3 unlock_timeout={{ rhel9cis_pam_faillock_unlock_time }}" }
- { regexp: account\s*required\s*pam_faillock.so, before: account\s*required\s*pam_unix.so, line: "account required pam_faillock.so" }
- name: "5.3.2.3 | PATCH | Ensure pam_pwquality module is enabled"
when:

View file

@ -23,7 +23,7 @@
- rhel9cis_disruption_high
ansible.builtin.replace:
path: "/etc/pam.d/{{ item }}-auth"
regexp: ^(\s*auth\s+(?:requisite|required|sufficient)\s+pam_faillock\.so)(.*)\s+deny\s*=\s*\S+(.*$)
regexp: ^(\s*auth\s+(requisite|required|sufficient)\s+pam_faillock\.so)(.*)\s+deny\s*=\s*\S+(.*$)
replace: \1 \2\3
loop:
- password

View file

@ -24,13 +24,12 @@
ansible.builtin.shell: "awk -F: '(/^[^:]+:[^!*]/ && ($5> {{ rhel9cis_pass_max_days }} || $5< {{ rhel9cis_pass_max_days }} || $5 == -1)){print $1}' /etc/shadow"
changed_when: false
failed_when: false
check_mode: false
register: discovered_max_days
- name: "5.4.1.1 | PATCH | Ensure password expiration is 365 days or less | Set existing users PASS_MAX_DAYS"
when:
- discovered_max_days.stdout_lines | length > 0
- item in prelim_interactive_users | map(attribute='username') | list
- item in prelim_interactive_usernames.stdout
- rhel9cis_force_user_maxdays
ansible.builtin.user:
name: "{{ item }}"
@ -61,11 +60,11 @@
- name: "5.4.1.2 | PATCH | Ensure minimum password days is configured | Set existing users PASS_MIN_DAYS"
when:
- discovered_min_days.stdout_lines | length > 0
- item in prelim_interactive_users | map(attribute='username') | list
- item in prelim_interactive_usernames.stdout
- rhel9cis_force_user_mindays
ansible.builtin.user:
name: "{{ item }}"
password_expire_min: "{{ rhel9cis_pass_min_days }}"
password_expire_max: "{{ rhel9cis_pass_min_days }}"
loop: "{{ discovered_min_days.stdout_lines }}"
- name: "5.4.1.3 | PATCH | Ensure password expiration warning days is configured"
@ -92,9 +91,9 @@
- name: "5.4.1.3 | PATCH | Ensure password expiration warning days is configured | Set existing users WARN_DAYS"
when:
- discovered_warn_days.stdout_lines | length > 0
- item in prelim_interactive_users | map(attribute='username') | list
- item in prelim_interactive_usernames.stdout
- rhel9cis_force_user_warnage
ansible.builtin.command: "chage --warndays {{ rhel9cis_pass_warn_age }} {{ item }}"
ansible.builtin.command: "chage --warndays {{ rhel9cis_pass['warn_age'] }} {{ item }}"
changed_when: true
loop: "{{ discovered_warn_days.stdout_lines }}"
@ -141,7 +140,7 @@
register: discovered_passwdlck_user_list
- name: "5.4.1.5 | PATCH | Ensure inactive password lock is 30 days or less | Apply Inactive setting to existing accounts"
when: item in prelim_interactive_users | map(attribute='username') | list
when: item in prelim_interactive_usernames.stdout
ansible.builtin.command: chage --inactive {{ rhel9cis_inactivelock.lock_days }} "{{ item }}"
changed_when: true
loop: "{{ discovered_passwdlck_user_list.stdout_lines }}"

View file

@ -61,7 +61,7 @@
- level1-server
- level1-workstation
- patch
- rule_5.4.2.3
- rule_5.4.2.2
- user
- system
- NIST800-53R5_CM-1
@ -135,22 +135,6 @@
ansible.builtin.set_fact:
root_paths: "{{ discovered_root_paths.stdout }}"
- name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Check for presence of non-dirs"
ansible.builtin.stat:
path: "{{ item }}"
loop: "{{ discovered_root_paths_split.stdout_lines }}"
register: discovered_root_paths_stat
- name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Create dirs for some paths that are not dirs"
ansible.builtin.file:
path: "{{ item.item }}"
state: directory
owner: root
group: root
mode: 'go-w'
loop: "{{ discovered_root_paths_stat.results }}"
when: not item.stat.exists
- name: "5.4.2.5 | AUDIT | Ensure root PATH Integrity | Check for empty dirs"
when: discovered_root_paths is defined
ansible.builtin.shell: 'echo {{ root_paths }} | grep -q "::" && echo "roots path contains a empty directory (::)"'
@ -206,12 +190,12 @@
regexp: \s*umask
line: "umask {{ rhel9cis_root_umask }}"
create: true
mode: 'u-x,go-rwx'
mode: 'u+x,go-rwx'
- name: "5.4.2.7 | PATCH | Ensure system accounts do not have a valid login shell"
when:
- rhel9cis_rule_5_4_2_7
- "item.id not in prelim_interactive_users | map(attribute='username')"
- "item.id not in prelim_interactive_usernames.stdout"
- item.id not in rhel9cis_system_users_shell
- "'root' not in item.id"
- rhel9cis_disruption_high
@ -228,7 +212,7 @@
ansible.builtin.user:
name: "{{ item.id }}"
shell: /usr/sbin/nologin
loop: "{{ prelim_captured_passwd_data }}"
loop: "{{ rhel9cis_passwd }}"
loop_control:
label: "{{ item.id }}"
@ -236,7 +220,7 @@
when:
- rhel9cis_rule_5_4_2_8
- rhel9cis_disruption_high
- "item.id not in prelim_interactive_users | map(attribute='username')"
- "item.id not in prelim_interactive_usernames.stdout"
- "'root' not in item.id"
tags:
- level1-server
@ -251,6 +235,6 @@
ansible.builtin.user:
name: "{{ item.id }}"
password_lock: true
loop: "{{ prelim_captured_passwd_data }}"
loop: "{{ rhel9cis_passwd }}"
loop_control:
label: "{{ item.id }}"

View file

@ -5,56 +5,45 @@
- name: "SECTION | 5.1 | Configure SSH Server"
when:
- "'openssh-server' in ansible_facts.packages"
- rhel9cis_section5_1
ansible.builtin.import_tasks:
file: cis_5.1.x.yml
- name: "SECTION | 5.2 | Configure privilege escalation"
when:
- rhel9cis_section5_2
ansible.builtin.import_tasks:
file: cis_5.2.x.yml
- name: "SECTION | 5.3"
when:
- rhel9cis_section5_3
block:
- name: "SECTION | 5.3.1.x | Configure PAM software packages"
ansible.builtin.import_tasks:
file: cis_5.3.1.x.yml
- name: "SECTION | 5.3.1.x | Configure PAM software packages"
ansible.builtin.import_tasks:
file: cis_5.3.1.x.yml
- name: "SECTION | 5.3.2.x | Configure authselect"
ansible.builtin.import_tasks:
file: cis_5.3.2.x.yml
- name: "SECTION | 5.3.2.x | Configure authselect"
ansible.builtin.import_tasks:
file: cis_5.3.2.x.yml
- name: "SECTION | 5.3.3.1.x | Configure pam_faillock module"
ansible.builtin.import_tasks:
file: cis_5.3.3.1.x.yml
- name: "SECTION | 5.3.3.1.x | Configure pam_faillock module"
ansible.builtin.import_tasks:
file: cis_5.3.3.1.x.yml
- name: "SECTION | 5.3.3.2.x | Configure pam_pwquality module"
ansible.builtin.import_tasks:
file: cis_5.3.3.2.x.yml
- name: "SECTION | 5.3.3.2.x | Configure pam_pwquality module"
ansible.builtin.import_tasks:
file: cis_5.3.3.2.x.yml
- name: "SECTION | 5.3.3.3.x | Configure pam_pwhistory module"
ansible.builtin.import_tasks:
file: cis_5.3.3.3.x.yml
- name: "SECTION | 5.3.3.3.x | Configure pam_pwhistory module"
ansible.builtin.import_tasks:
file: cis_5.3.3.3.x.yml
- name: "SECTION | 5.3.3.4.x | Configure pam_unix module"
ansible.builtin.import_tasks:
file: cis_5.3.3.4.x.yml
- name: "SECTION | 5.3.3.4.x | Configure pam_unix module"
ansible.builtin.import_tasks:
file: cis_5.3.3.4.x.yml
- name: "SECTION | 5.4"
when:
- rhel9cis_section5_4
block:
- name: "SECTION | 5.4.1.x | Configure shadow password suite parameters"
ansible.builtin.import_tasks:
file: cis_5.4.1.x.yml
- name: "SECTION | 5.4.1.x | Configure shadow password suite parameters"
ansible.builtin.import_tasks:
file: cis_5.4.1.x.yml
- name: "SECTION | 5.4.2.x | Configure root and system accounts and environment"
ansible.builtin.import_tasks:
file: cis_5.4.2.x.yml
- name: "SECTION | 5.4.2.x | Configure root and system accounts and environment"
ansible.builtin.import_tasks:
file: cis_5.4.2.x.yml
- name: "SECTION | 5.4.3.x | Configure user default environment"
ansible.builtin.import_tasks:
file: cis_5.4.3.x.yml
- name: "SECTION | 5.4.3.x | Configure user default environment"
ansible.builtin.import_tasks:
file: cis_5.4.3.x.yml

View file

@ -58,10 +58,6 @@
dest: /var/lib/aide/aide.db.gz
remote_src: true
mode: 'ug-wx,o-rwx'
register: aide_db_cp
failed_when:
- not ansible_check_mode
- aide_db_cp.failed
- name: "6.1.2 | PATCH | Ensure filesystem integrity is regularly checked"
when:
@ -91,13 +87,13 @@
- name: "6.1.2 | PATCH | Ensure filesystem integrity is regularly checked | aide service"
when: rhel9cis_aide_scan == "timer"
ansible.builtin.systemd:
ansible.builtin.systemd_service:
name: aidecheck.service
enabled: true
- name: "6.1.2 | PATCH | Ensure filesystem integrity is regularly checked | aide service"
when: rhel9cis_aide_scan == "timer"
ansible.builtin.systemd:
ansible.builtin.systemd_service:
name: aidecheck.timer
state: started
enabled: true
@ -123,7 +119,4 @@
/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512
/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512
/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512
register: aide_file_integrity_check
failed_when:
- not ansible_check_mode
- aide_file_integrity_check.failed
validate: aide -D --config %s

View file

@ -96,20 +96,15 @@
- rule_6.2.1.4
block:
- name: "6.2.1.4 | PATCH | Ensure only one logging system is in use | when rsyslog"
when:
- rhel9cis_syslog == "rsyslog"
- "'systemd-journald' in ansible_facts.packages"
when: rhel9cis_syslog == "rsyslog"
ansible.builtin.systemd:
name: systemd-journald
state: stopped
enabled: false
- name: "6.2.1.4 | PATCH | Ensure only one logging system is in use | when journald"
when:
- rhel9cis_syslog == "journald"
- "'rsyslog' in ansible_facts.packages"
when: rhel9cis_syslog == "journald"
ansible.builtin.systemd:
name: rsyslog
state: stopped
enabled: false
register: discovered_rsyslog_service

View file

@ -17,7 +17,7 @@
name: systemd-journal-remote
state: present
- name: "6.2.2.1.2 | PATCH | Ensure systemd-journal-upload authentication is configured"
- name: "6.2.2.1.2 | PATCH | Ensure systemd-journal-remote authentication is configured"
when:
- rhel9cis_rule_6_2_2_1_2
- not rhel9cis_system_is_log_server
@ -35,12 +35,12 @@
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { regexp: 'URL=', line: 'URL={{ rhel9cis_journal_upload_url }}'}
- { regexp: 'URL=', line: 'URL={{ rhel9cis_remote_log_server }}'}
- { regexp: 'ServerKeyFile=', line: 'ServerKeyFile={{ rhel9cis_journal_upload_serverkeyfile }}'}
- { regexp: 'ServerCertificateFile=', line: 'ServerCertificateFile={{ rhel9cis_journal_servercertificatefile }}'}
- { regexp: 'TrustedCertificateFile=', line: 'TrustedCertificateFile={{ rhel9cis_journal_trustedcertificatefile }}'}
- name: "6.2.2.1.3 | PATCH | Ensure systemd-journal-upload is enabled and active"
- name: "6.2.2.1.3 | PATCH | Ensure systemd-journal-remote is enabled and active"
when:
- not rhel9cis_system_is_log_server
- rhel9cis_rule_6_2_2_1_3

View file

@ -50,7 +50,7 @@
- name: "6.2.2.3 | PATCH | Ensure journald Compress is configured | comment out current entries"
ansible.builtin.replace:
path: /etc/systemd/journald.conf
regexp: (?i)(\s*compress=)
regexp: ^(?i)(\s*compress=)
replace: '#\1'
- name: "6.2.2.4 | PATCH | Ensure journald Storage is configured"
@ -76,5 +76,5 @@
- name: "6.2.2.4 | PATCH | Ensure journald Storage is configured | comment out current entries"
ansible.builtin.replace:
path: /etc/systemd/journald.conf
regexp: (?i)(\s*storage=)
regexp: ^(?i)(\s*storage=)
replace: '#\1'

View file

@ -131,7 +131,7 @@
*.=warning;*.=err -/var/log/warn
*.crit /var/log/warn
*.*;mail.none;news.none /var/log/messages
insertbefore: '# ### sample forwarding rule ###'
insertafter: '#### RULES ####'
notify: Restart rsyslog
- name: "6.2.3.5 | PATCH | Ensure logging is configured | Local log settings"
@ -256,8 +256,8 @@
- name: "6.2.3.8 | PATCH | Ensure logrotate is configured | set rsyslog conf"
ansible.builtin.template:
src: etc/logrotate.d/rsyslog_log.j2
dest: /etc/logrotate.d/rsyslog_log
src: etc/logrotate.d/rsyslog.conf.j2
dest: /etc/logrotate.d/rsyslog.conf
owner: root
group: root
mode: 'g-wx,o-rwx'

View file

@ -8,8 +8,6 @@
- patch
- logfiles
- rule_6.2.4.1
- NIST800-53R5_AC-3
- NIST800-53R5_MP-2
block:
- name: "6.2.4.1 | AUDIT | Ensure access to all logfiles has been configured | find log files"
ansible.builtin.shell: find /var/log/ -type f -exec ls {} \;
@ -17,35 +15,43 @@
failed_when: false
register: discovered_logfiles
- name: "6.2.4.1 | PATCH | Ensure access to all logfiles has been configured | change permissions SSSD min 660"
- name: "6.2.4.1 | PATCH | Ensure access to all logfiles has been configured | change permissions"
when:
- discovered_logfiles.stdout_lines | length > 0
- item is match("/var/log/(gdm|sssd)")
ansible.builtin.file:
path: "{{ item }}"
mode: 'ug-x,o-rwx'
failed_when: discovered_logfile_list.state not in '[ file, absent ]'
register: discovered_logfile_list
loop: "{{ discovered_logfiles.stdout_lines }}"
- name: "6.2.4.1 | PATCH | Ensure access to all logfiles has been configured | change permissions tmp min 664"
when:
- discovered_logfiles.stdout_lines | length > 0
- item is match("/var/log/((u|b|w)tmp*|lastlog)")
ansible.builtin.file:
path: "{{ item }}"
mode: 'ug-x,o-wx'
failed_when: discovered_logfile_list.state not in '[ file, absent ]'
register: discovered_logfile_list
loop: "{{ discovered_logfiles.stdout_lines }}"
- name: "6.2.4.1 | PATCH | Ensure access to all logfiles has been configured | change permissions else all 640"
when:
- discovered_logfiles.stdout_lines | length > 0
- item is not match("/var/log/((u|b|w)tmp*|lastlog|sssd)")
- ('audit.log' in item or 'journal' in item) or
item == '/var/log/secure' or
item == '/var/log/syslog' or
item == '/var/log/messages' or
item == '/var/log/auth.log'
ansible.builtin.file:
path: "{{ item }}"
mode: 'u-x,g-wx,o-rwx'
failed_when: discovered_logfile_list.state not in '[ file, absent ]'
register: discovered_logfile_list
loop: "{{ discovered_logfiles.stdout_lines }}"
- name: "6.2.4.1 | PATCH | Ensure access to all logfiles has been configured | change permissions"
when:
- discovered_logfiles.stdout_lines | length > 0
- ('anaconda' in item or 'dnf' in item or 'secure' in item or 'messages' in item or 'hawkey' in item)
ansible.builtin.file:
path: "{{ item }}"
mode: 'u-x,g-x,o-rwx'
failed_when: discovered_logfile_list.state not in '[ file, absent ]'
register: discovered_logfile_list
loop: "{{ discovered_logfiles.stdout_lines }}"
- name: "6.2.4.1 | PATCH | Ensure access to all logfiles has been configured | change permissions"
when:
- discovered_logfiles.stdout_lines | length > 0
- ('sssd' in item or 'lastlog' in item) or
item == "/var/log/btmp" or
item == "/var/log/utmp" or
item == "/var/log/wtmp" or
item == "/var/log/lastlog"
ansible.builtin.file:
path: "{{ item }}"
mode: 'ug-x,o-wx'
failed_when: discovered_logfile_list.state not in '[ file, absent ]'
register: discovered_logfile_list
loop: "{{ discovered_logfiles.stdout_lines }}"

View file

@ -27,9 +27,9 @@
- level2-workstation
- patch
- auditd
- rule_6.3.4.1
- rule_6.3.4.2
- rule_6.3.4.3
- rule_6.3.4.4
- NIST800-53R5_AU-3
ansible.builtin.file:
path: "{{ prelim_auditd_logfile.stdout }}"

View file

@ -5,7 +5,6 @@
file: cis_6.1.x.yml
- name: "SECTION | 6.2.1 | Configure systemd-journald service"
when: rhel9cis_syslog == 'journald'
ansible.builtin.import_tasks:
file: cis_6.2.1.x.yml
@ -20,9 +19,7 @@
file: cis_6.2.2.x.yml
- name: "SECTION | 6.2.3 | Configure rsyslog"
when:
- rhel9cis_syslog == 'rsyslog'
- rhel9cis_rsyslog_ansiblemanaged
when: rhel9cis_syslog == 'rsyslog'
ansible.builtin.import_tasks:
file: cis_6.2.3.x.yml

View file

@ -169,8 +169,6 @@
owner: root
group: root
mode: 'u-x,go-wx'
failed_when: discovered_file_exists.state not in '[ file, absent ]'
register: discovered_file_exists
- name: "7.1.11 | PATCH | Ensure world writable files and directories are secured"
when:

View file

@ -220,7 +220,7 @@
- name: "7.2.7 | AUDIT | Ensure no duplicate group names exist | Print warning about users with duplicate group names"
when: discovered_group_check.stdout | length > 0
ansible.builtin.debug:
msg: "Warning!! The following group names are duplicates: {{ discovered_group_check.stdout_lines }}"
msg: "Warning!! The following group names are duplicates: {{ discovered_group_group_check.stdout_lines }}"
- name: "7.2.7 | AUDIT | Ensure no duplicate group names exist | Set warning count"
when: discovered_group_check.stdout | length > 0
@ -243,7 +243,7 @@
state: directory
owner: "{{ item.id }}"
group: "{{ item.gid }}"
loop: "{{ prelim_captured_passwd_data | selectattr('uid', '>=', prelim_min_int_uid | int) | selectattr('uid', '<=', prelim_max_int_uid | int) | list }}"
loop: "{{ rhel9cis_passwd | selectattr('uid', '>=', prelim_min_int_uid | int) | selectattr('uid', '<=', prelim_max_int_uid | int) | list }}"
loop_control:
label: "{{ item.id }}"
@ -256,7 +256,7 @@
etype: group
permissions: rx
state: present
loop: "{{ prelim_interactive_users | map(attribute='home') | list }}"
loop: "{{ prelim_interactive_users_home.stdout_lines }}"
- name: "7.2.8 | PATCH | Ensure local interactive user home directories are configured | Set other ACL"
when: not system_is_container
@ -266,7 +266,7 @@
etype: other
permissions: 0
state: present
loop: "{{ prelim_interactive_users | map(attribute='home') | list }}"
loop: "{{ prelim_interactive_users_home.stdout_lines }}"
- name: "7.2.9 | PATCH | Ensure local interactive user dot files access is configured"
when:
@ -286,8 +286,8 @@
vars:
warn_control_id: '7.2.9'
block:
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured"
ansible.builtin.shell: find {{ prelim_interactive_users_home.stdout_lines | list | join(' ') }} -name "\.*" -type f
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Check for files"
ansible.builtin.shell: find /home/ -name "\.*"
changed_when: false
failed_when: discovered_homedir_hidden_files.rc not in [ 0, 1 ]
check_mode: false
@ -296,63 +296,25 @@
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Warning on files found"
when:
- discovered_homedir_hidden_files.stdout | length > 0
- not rhel9cis_dotperm_ansiblemanaged
- rhel9cis_dotperm_ansiblemanaged
ansible.builtin.debug:
msg:
- "Warning!! Please investigate that hidden files found in users home directories match control requirements."
- "Warning!! We have discovered group or world-writable dot files on your system and this host is configured for manual intervention. Please investigate these files further."
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Set warning count"
when:
- discovered_homedir_hidden_files.stdout | length > 0
- not rhel9cis_dotperm_ansiblemanaged
ansible.builtin.import_tasks:
file: warning_facts.yml
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured"
- name: "7.2.9 | PATCH | Ensure local interactive user dot files access is configured | Set warning count"
when:
- discovered_homedir_hidden_files.stdout | length > 0
- rhel9cis_dotperm_ansiblemanaged
block:
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Changes files if configured .bash_history & .netrc"
when:
- discovered_homedir_hidden_files.stdout | length > 0
- item | basename in ['.bash_history','.netrc']
ansible.builtin.file:
path: "{{ item }}"
mode: 'u-x,go-rwx'
failed_when: discovered_dot_bash_history_to_change.state not in '[ file, absent ]'
register: discovered_dot_bash_history_to_change
loop: "{{ discovered_homedir_hidden_files.stdout_lines }}"
ansible.builtin.import_tasks:
file: warning_facts.yml
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Changes files if configured file mode"
ansible.builtin.file:
path: '{{ item }}'
mode: 'u-x,go-wx'
failed_when: discovered_dot_bash_history_to_change.state not in '[ file, absent ]'
register: discovered_dot_bash_history_to_change
loop: "{{ discovered_homedir_hidden_files.stdout_lines }}"
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Changes files ownerships"
ansible.builtin.file:
path: "{{ item }}"
owner: "{{ prelim_captured_passwd_data | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='uid') | last }}"
group: "{{ prelim_captured_passwd_data | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='gid') | last }}"
failed_when: discovered_dot_bash_history_to_change.state not in '[ file, absent ]'
register: discovered_dot_bash_history_to_change
loop: "{{ discovered_homedir_hidden_files.stdout_lines }}"
- name: "7.2.9 | PATCH | Ensure local interactive user dot files access is configured | Changes files if configured"
ansible.builtin.file:
path: '{{ item }}'
mode: 'go-w'
owner: "{{ prelim_captured_passwd_data | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='uid') | last }}"
group: "{{ prelim_captured_passwd_data | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='gid') | last }}"
with_items: "{{ discovered_homedir_hidden_files.stdout_lines }}"
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | rename .forward or .rhosts files"
when:
- item | basename in ['.forward','.rhosts']
- item is not search ("CIS")
ansible.builtin.command: "mv {{ item }} {{ item }}_CIS_TOBEREVIEWED"
changed_when: true
loop: "{{ discovered_homedir_hidden_files.stdout_lines }}"
- name: "7.2.9 | PATCH | Ensure local interactive user dot files access is configured | Changes files if configured"
when:
- discovered_homedir_hidden_files.stdout | length > 0
- rhel9cis_dotperm_ansiblemanaged
ansible.builtin.file:
path: '{{ item }}'
mode: 'go-w'
owner: "{{ rhel9cis_passwd | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='uid') | last }}"
group: "{{ rhel9cis_passwd | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='gid') | last }}"
with_items: "{{ discovered_homedir_hidden_files.stdout_lines }}"

View file

@ -34,10 +34,10 @@ rhel9cis_selinux_disable: {{ rhel9cis_selinux_disable }}
# UEFI boot('/etc/grub2-efi.cfg') or in case of BIOS legacy-boot('/etc/grub2.cfg').
rhel9cis_legacy_boot: {{ rhel9cis_legacy_boot }}
## Benchmark name used by auditing control role
## Benchmark name used by audting control role
# The audit variable found at the base
## metadata for Audit benchmark
benchmark_version: {{ benchmark_version }}
benchmark_version: 'v2.0.0'
benchmark: RHEL9-CIS
@ -151,7 +151,7 @@ rhel9cis_rule_1_8_8: {{ rhel9cis_rule_1_8_8 }}
rhel9cis_rule_1_8_9: {{ rhel9cis_rule_1_8_9 }}
rhel9cis_rule_1_8_10: {{ rhel9cis_rule_1_8_10 }}
# Section 2 rules are controlling Services (Special Purpose Services, and service clients)
# Section 2 rules are controling Services (Special Purpose Services, and service clients)
## Configure Server Services
rhel9cis_rule_2_1_1: {{ rhel9cis_rule_2_1_1 }}
rhel9cis_rule_2_1_2: {{ rhel9cis_rule_2_1_2 }}
@ -625,21 +625,21 @@ rhel9cis_authselect_custom_profile_name: {{ rhel9cis_authselect_custom_profile_n
# These are discovered via logins.def if set true
rhel9cis_discover_int_uid: {{ rhel9cis_discover_int_uid }}
# This variable sets the minimum number from which to search for UID
# Note that the value will be dynamically overwritten if variable `discover_int_uid` has
# Note that the value will be dynamically overwritten if variable `dicover_int_uid` has
# been set to `true`.
min_int_uid: 1000
### Controls:
# - Ensure local interactive user home directories exist
# - Ensure local interactive users own their home directories
# This variable sets the maximum number at which the search stops for UID
# Note that the value will be dynamically overwritten if variable `discover_int_uid` has
# Note that the value will be dynamically overwritten if variable `dicover_int_uid` has
# been set to `true`.
max_int_uid: 65533
## Section6 vars
## Control 6.1.2 AIDE schedule
# how aide scheduler runs can be one of cron or timer
# how aide sceduler runs can be one of cron or timer
rhel9cis_aide_scan: {{ rhel9cis_aide_scan }}
# These are the crontab settings for periodical checking of the filesystem's integrity using AIDE.

View file

@ -10,7 +10,12 @@
{% endif %}
{% if rhel9cis_rule_6_3_3_2 %}
{% set syscalls = ["execve"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
{% set arch_syscalls = [] %}
{%- for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append(syscall) }}
{% endif %}
{% endfor -%}
-a always,exit -F arch=b64 -C euid!=uid -F auid!=unset -S {{ arch_syscalls|join(',') }} -k user_emulation
-a always,exit -F arch=b32 -C euid!=uid -F auid!=unset -S {{ arch_syscalls|join(',') }} -k user_emulation
{% endif %}
@ -18,28 +23,31 @@
-w {{ rhel9cis_sudolog_location }} -p wa -k sudo_log_file
{% endif %}
{% if rhel9cis_rule_6_3_3_4 %}
{% set syscalls = ["adjtimex","settimeofday"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
{% set arch_syscalls = [] %}
{% for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append(syscall) }}
{% endif %}
{% endfor %}
-a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -k time-change
-a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -k time-change
{% set syscalls = ["clock_settime"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
-a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F a0=0x0 -k time-change
-a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F a0=0x0 -k time-change
-w /etc/localtime -p wa -k time-change
{% endif %}
{% if rhel9cis_rule_6_3_3_5 %}
{% set syscalls = ["sethostname","setdomainname"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
-a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -k system-locale
-a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -k system-locale
{% set arch_syscalls = [] %}
{% for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append(syscall) }}
{% endif %}
{% endfor %}
-a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -k system-locale
-a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -k system-locale
-w /etc/issue -p wa -k system-locale
-w /etc/issue.net -p wa -k system-locale
-w /etc/hosts -p wa -k system-locale
-w /etc/hostname -p wa -k system-locale
-w /etc/sysconfig/network -p wa -k system-locale
-w /etc/sysconfig/network-scripts -p wa -k system-locale
-w /etc/NetworkManager -p wa -k system-locale
{% endif %}
{% if rhel9cis_rule_6_3_3_6 %}
{% for proc in discovered_priv_procs.stdout_lines -%}
@ -48,7 +56,12 @@
{% endif %}
{% if rhel9cis_rule_6_3_3_7 %}
{% set syscalls = ["creat","open","openat","truncate","ftruncate"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
{% set arch_syscalls = [] %}
{% for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append(syscall) }}
{% endif %}
{% endfor %}
-a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F exit=-EACCES -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k access
-a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F exit=-EPERM -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k access
-a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F exit=-EACCES -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k access
@ -66,27 +79,62 @@
{% endif %}
{% if rhel9cis_rule_6_3_3_9 %}
{% set syscalls = ["chmod","fchmod","fchmodat"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
{% set arch_syscalls = [] %}
{% for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append(syscall) }}
{% endif %}
{% endfor %}
-a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_mod
{% set syscalls = ["chown","fchown","lchown","fchownat"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
{% set arch_syscalls = [] %}
{% for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append(syscall) }}
{% endif %}
{% endfor %}
-a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_mod
{% set syscalls = ["setxattr","lsetxattr","fsetxattr","removexattr","lremovexattr","fremovexattr"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
{% set arch_syscalls = [] %}
{% for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append(syscall) }}
{% endif %}
{% endfor %}
-a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_mod
{% set syscalls = ["chmod","fchmod","fchmodat"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
{% set arch_syscalls = [] %}
{% for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append(syscall) }}
{% endif %}
{% endfor %}
-a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_mod
{% set syscalls = ["chown","fchown","lchown","fchownat"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
{% set arch_syscalls = [] %}
{% for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append(syscall) }}
{% endif %}
{% endfor %}
-a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_mod
{% set syscalls = ["setxattr","lsetxattr","fsetxattr","removexattr","lremovexattr","fremovexattr"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
{% set arch_syscalls = [] %}
{% for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append(syscall) }}
{% endif %}
{% endfor %}
-a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_mod
{% endif %}
{% if rhel9cis_rule_6_3_3_10 %}
{% set syscalls = ["mount"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
{% set arch_syscalls = [] %}
{% for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append(syscall) }}
{% endif %}
{% endfor %}
-a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k mounts
-a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k mounts
{% endif %}
@ -101,7 +149,12 @@
{% endif %}
{% if rhel9cis_rule_6_3_3_13 %}
{% set syscalls = ["unlink","unlinkat","rename","renameat"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
{% set arch_syscalls = [] %}
{% for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append( syscall) }}
{% endif %}
{% endfor %}
-a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k delete
-a always,exit -F arch=b32 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k delete
{% endif %}
@ -116,7 +169,7 @@
-a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_chng
{% endif %}
{% if rhel9cis_rule_6_3_3_17 %}
-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k perm_chng
-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k priv_chng
{% endif %}
{% if rhel9cis_rule_6_3_3_18 %}
-a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k usermod
@ -124,7 +177,12 @@
{% if rhel9cis_rule_6_3_3_19 %}
-a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k kernel_modules
{% set syscalls = ["init_module","finit_module","delete_module","create_module","query_module"] %}
{% set arch_syscalls = syscalls | select("in", supported_syscalls) | list %}
{% set arch_syscalls = [] %}
{% for syscall in syscalls %}
{% if syscall in supported_syscalls %}
{{ arch_syscalls.append( syscall) }}
{% endif %}
{% endfor %}
-a always,exit -F arch=b64 -S {{ arch_syscalls|join(',') }} -F auid>={{ prelim_min_int_uid }} -F auid!=unset -k kernel_modules
{% endif %}
{% if rhel9cis_rule_6_3_3_20 %}

View file

@ -1,40 +0,0 @@
# CIS Hardening Carried out
# Added as part of ansible-lockdown CIS baseline
# provided by Mindpoint Group - A Tyto Athene Company
[lockdown_details]
# Benchmark release
Benchmark_release = CIS-{{ benchmark_version }}
Benchmark_run_date = {{ '%Y-%m-%d - %H:%M:%S' | ansible.builtin.strftime }}
# If options set (doesn't mean it ran all controls)
level_1_hardening_enabled = {{ rhel9cis_level_1 }}
level_2_hardening_enabled = {{ rhel9cis_level_2 }}
{% if ansible_run_tags | length > 0 %}
# If tags used to stipulate run level
{% if 'level1-server' in ansible_run_tags %}
Level_1_Server_tag_run = true
{% endif %}
{% if 'level2-server' in ansible_run_tags %}
Level_2_Server_tag_run = true
{% endif %}
{% if 'level1-workstation' in ansible_run_tags %}
Level_1_workstation_tag_run = true
{% endif %}
{% if 'level2-workstation' in ansible_run_tags %}
Level_2_workstation_tag_run = true
{% endif %}
{% endif %}
[lockdown_audit_details]
{% if run_audit %}
# Audit run
audit_run_date = {{ '%Y-%m-%d - %H:%M:%S' | ansible.builtin.strftime }}
audit_file_local_location = {{ audit_log_dir }}
{% if not audit_only %}
audit_summary = {{ post_audit_results }}
{% endif %}
{% if fetch_audit_output %}
audit_files_centralized_location = {{ audit_output_destination }}
{% endif %}
{% endif %}

View file

@ -1,4 +1,4 @@
# This is a subpolicy to disable weak ciphers
# for the SSH protocol (libssh and OpenSSH)
# Carried out as part of CIS Benchmark rules combined 1.6.6 and 5.1.4
cipher@SSH ={% if rhel9cis_rule_1_6_6 %} -CHACHA20-POLY1305{% endif %}{% if rhel9cis_rule_5_1_4 %} -3DES-CBC -AES-128-CBC -AES-192-CBC -AES-256-CBC{% endif %}
cipher@SSH ={% if rhel9cis_rule_1_6_6 %} -CHACHA20-POLY1305{% endif %}{% if rhel9cis_rule_5_1_5 %} -3DES-CBC -AES-128-CBC -AES-192-CBC -AES-256-CBC{% endif %}

View file

@ -4,4 +4,4 @@
[org/gnome/login-screen]
banner-message-enable=true
banner-message-text="{{ rhel9cis_warning_banner | trim | replace("\n", "\\n") }}"
banner-message-text="{{ rhel9cis_warning_banner }}"

View file

@ -0,0 +1,11 @@
/var/log/rsyslog/*.log {
{{ rhel9cis_rsyslog_logrotate_rotated }}
rotate {{ rhel9cis_rsyslog_logrotate_keep }}
{% if rhel9cis_rsyslog_logrotate_compress %}compress{% else %}nocompress{% endif %}
{% if rhel9cis_rsyslog_logrotate_missingok %}missingok{% else %}missingok{% endif %}
{% if rhel9cis_rsyslog_logrotate_notifempty %}notifempty{% else %}ifempty{% endif %}
{% if rhel9cis_rsyslog_logrotate_create %}create {{ rhel9cis_rsyslog_logrotate_create_opts }}{% endif %}
postrotate
/usr/bin/systemctl reload rsyslog.service >/dev/null || true
endscript
}

View file

@ -1,26 +0,0 @@
/var/log/rsyslog/*.log {
{{ rhel9cis_rsyslog_logrotate_rotated_when }}
rotate {{ rhel9cis_rsyslog_logrotate_rotatation_keep }}
{% if rhel9cis_rsyslog_logrotate_compress %}
compress
{% else %}
nocompress
{% endif %}
{% if rhel9cis_rsyslog_logrotate_missingok %}
missingok
{% else %}
nomissingok
{% endif %}
{% if rhel9cis_rsyslog_logrotate_notifempty %}
notifempty
{% else %}
ifempty
{% endif %}
{% if rhel9cis_rsyslog_logrotate_create %}
create{% if rhel9cis_rsyslog_logrotate_create_opts is defined %} {{ rhel9cis_rsyslog_logrotate_create_opts }}{% endif %}
{% endif %}
postrotate
/usr/bin/systemctl reload rsyslog.service >/dev/null || true
endscript
}

View file

@ -4,7 +4,4 @@
{% if rhel9cis_rule_3_1_1 and not rhel9cis_ipv6_required %}
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
{% for interface in ansible_interfaces %}
net.ipv6.conf.{{ interface }}.disable_ipv6 = 1
{% endfor %}
{% endif %}

View file

@ -7,16 +7,10 @@ rhel9cis_allowed_crypto_policies:
- 'FUTURE'
- 'FIPS'
# Following is left blank for ability to build string
rhel9cis_crypto_policy_module: ''
# Do not adjust these are recognized as part of the CIS benchmark and used during testing
rhel9cis_allowed_crypto_policies_modules:
# Recognized by CIS as possible extra options
- 'OSPP'
- 'AD-SUPPORT'
- 'AD-SUPPORT-LEGACY'
# The following are already included in 1.6.x controls
- 'NO-SHA1'
- 'NO-SSHCBC'
- 'NO-SSHETM'
@ -28,12 +22,6 @@ rhel9cis_allowed_crypto_policies_modules:
warn_control_list: ""
warn_count: 0
# list of dicts of interactive users, filled in during prelim.yml
prelim_interactive_users: []
# Default empty values for 1.4.2
efi_mount_opts_addition: ''
gpg_key_package: "{{ ansible_facts.distribution | lower }}-gpg-keys"
## Controls 6.3.3.x - Audit template