Skip to content

Commit

Permalink
Merge pull request ansible-lockdown#49 from ansible-lockdown/audit_sc…
Browse files Browse the repository at this point in the history
…ript_update

Audit script update
  • Loading branch information
uk-bolly authored Sep 14, 2023
2 parents fbf2faa + 95810be commit 45dbfb8
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 96 deletions.
66 changes: 66 additions & 0 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
Contributing to MindPoint Group Projects
========================================

Rules
-----
1) All commits must be GPG signed (details in Signing section)
2) All commits must have Signed-off-by (Signed-off-by: Joan Doe <[email protected]>) in the commit message (details in Signing section)
3) All work is done in your own branch
4) All pull requests go into the devel branch. There are automated checks for signed commits, signoff in commit message, and functional testing)
5) Be open and nice to eachother

Workflow
--------
- Your work is done in your own individual branch. Make sure to to Signed-off and GPG sign all commits you intend to merge
- All community Pull Requests are into the devel branch. There are automated checks for GPG signed, Signed-off in commits, and functional tests before being approved. If your pull request comes in from outside of our repo, the pull request will go into a staging branch. There is info needed from our repo for our CI/CD testing.
- 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

Signing your contribution
-------------------------

We've chosen to use the Developer's Certificate of Origin (DCO) method
that is employed by the Linux Kernel Project, which provides a simple
way to contribute to MindPoint Group projects.

The process is to certify the below DCO 1.1 text
::

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or

(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or

(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.

(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
::

Then, when it comes time to submit a contribution, include the
following text in your contribution commit message:

::

Signed-off-by: Joan Doe <[email protected]>

::

This message can be entered manually, or if you have configured git
with the correct `user.name` and `user.email`, you can use the `-s`
option to `git commit` to automatically include the signoff message.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020 MindPoint Group
Copyright (c) 2023 MindPoint Group

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Tested on

## Requirements

You must have [goss](https://github.com/aelsabbahy/goss/) available to your host you would like to test.
You must have [goss](https://github.com/goss-org/goss/) available to your host you would like to test.

You must have sudo/root access to the system as some commands require privilege information.

Expand All @@ -46,13 +46,13 @@ Which will:

On our [Discord Server](https://discord.io/ansible-lockdown) to ask questions, discuss features, or just chat with other Ansible-Lockdown users

Set of configuration files and directories to run the first stages of CIS of RHEL 9 servers
Set of configuration files and directories to run the first stages of CIS of RHEL 8 servers

This is configured in a directory structure level.

Goss is run based on the goss.yml file in the top level directory. This specifies the configuration.

## further information

- [goss documentation](https://github.com/aelsabbahy/goss/blob/master/docs/manual.md#patterns)
- [goss documentation](https://github.com/goss-org/goss/blob/master/docs/manual.md#patterns)
- [CIS standards](https://www.cisecurity.org)
200 changes: 108 additions & 92 deletions run_audit.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,136 +8,134 @@
# 17 Dec 2021 - Added system_type variable - default Server will change to workstations with -w switch
# 02 Mar 2022 - Updated benchmark variable naming
# 06 Apr 2022 - Added format option in output inline with goss options e.g. json documentation this is for fault finding


#!/bin/bash

# 03 May 2022 - update for audit variables improvement added by @pavloos - https://github.com/ansible-lockdown/RHEL8-CIS-Audit/pull/29
# 10 Jun 2022 - added format output for different type - supports json,documentation or rspecish
# 04 Oct 2022 - Changed default content location to /opt
# 14 Sep 2023 - Tidyup of code,
# linting (thanks to @cf-sewe)
# Oracle included by default if RHEL family
# benchmark vars moved

# Variables in upper case tend to be able to be adjusted
# lower case variables are discovered or built from other variables

# Goss host Variables
AUDIT_BIN="${AUDIT_BIN:-/usr/local/bin/goss}" # location of the goss executable
AUDIT_FILE="${AUDIT_FILE:-goss.yml}" # the default goss file used by the audit provided by the audit configuration
AUDIT_CONTENT_LOCATION="${AUDIT_CONTENT_LOCATION:-/opt}" # Location of the audit configuration file as available to the OS


# Goss benchmark variables (these should not need changing unless new release)
BENCHMARK=CIS # Benchmark Name aligns to the audit
BENCHMARK_VER=2.0.0
BENCHMARK_OS=RHEL8


# Goss host Variables
AUDIT_BIN="${AUDIT_BIN:-/usr/local/bin/goss}" # location of the goss executable
AUDIT_BIN_MIN_VER="0.3.21"
AUDIT_FILE="${AUDIT_FILE:-goss.yml}" # the default goss file used by the audit provided by the audit configuration
AUDIT_CONTENT_LOCATION="${AUDIT_CONTENT_LOCATION:-/opt}" # Location of the audit configuration file as available to the OS

# help output
Help()
{
# Display Help
echo "Script to run the goss audit"
echo
echo "Syntax: $0 [-f|-g|-o|-v|-w|-h]"
echo "options:"
echo "-f optional - change the format output (default value = json)"
echo "-g optional - Add a group that the server should be grouped with (default value = ungrouped)"
echo "-o optional - file to output audit data"
echo "-v optional - relative path to thevars file to load (default e.g. $AUDIT_CONTENT_LOCATION/RHEL7-$BENCHMARK/vars/$BENCHMARK.yml)"
echo "-w optional - Sets the system_type to workstation (Default - Server)"
echo "-h Print this Help."
echo
# Display Help
echo "Script to run the goss audit"
echo
echo "Syntax: $0 [-f|-g|-o|-v|-w|-h]"
echo "options:"
echo "-f optional - change the format output (default value = json)"
echo "-g optional - Add a group that the server should be grouped with (default value = ungrouped)"
echo "-o optional - file to output audit data"
echo "-v optional - relative path to thevars file to load (default e.g. $AUDIT_CONTENT_LOCATION/RHEL7-$BENCHMARK/vars/$BENCHMARK.yml)"
echo "-w optional - Sets the system_type to workstation (Default - Server)"
echo "-h Print this Help."
echo
}


# Default vars that can be set
host_system_type=Server

## option statement
while getopts f:g:o:v::wh option; do
case "${option}" in
f ) FORMAT=${OPTARG} ;;
g ) GROUP=${OPTARG} ;;
o ) OUTFILE=${OPTARG} ;;
v ) VARS_PATH=${OPTARG} ;;
w ) host_system_type=Workstation ;;
h ) # display Help
Help
exit;;
? ) # Invalid option
echo "Invalid option: -${OPTARG}."
Help
exit;;
case "${option}" in
f ) FORMAT=${OPTARG} ;;
g ) GROUP=${OPTARG} ;;
o ) OUTFILE=${OPTARG} ;;
v ) VARS_PATH=${OPTARG} ;;
w ) host_system_type=Workstation ;;
h ) # display Help
Help
exit;;
? ) # Invalid option
echo "Invalid option: -${OPTARG}."
Help
exit;;
esac
done

#### Pre-Checks

# check access need to run as root or privileges due to some configuration access
if [ $(/usr/bin/id -u) -ne 0 ]; then
if [ "$(/usr/bin/id -u)" -ne 0 ]; then
echo "Script need to run with root privileges"
exit 1
fi

#### Main Script
#### Main Script ####

# Discover OS version aligning with audit
# Define os_vendor variable
if [ `grep -cE "fedora|rhel" /etc/os-release` != 0 ]; then
os_vendor="RHEL"
if [ "$(grep -Ec "rhel|oracle" /etc/os-release)" != 0 ]; then
os_vendor="RHEL"
else
os_vendor=`hostnamectl | grep Oper | cut -d : -f2 | awk '{print $1}' | tr a-z A-Z`
os_vendor="$(hostnamectl | grep Oper | cut -d : -f2 | awk '{print $1}' | tr '[:lower:]')"
fi

os_maj_ver=`grep -w VERSION_ID= /etc/os-release | awk -F\" '{print $2}' | cut -d '.' -f1`
os_maj_ver="$(grep -w VERSION_ID= /etc/os-release | awk -F\" '{print $2}' | cut -d '.' -f1)"
audit_content_version=$os_vendor$os_maj_ver-$BENCHMARK-Audit
audit_content_dir=$AUDIT_CONTENT_LOCATION/$audit_content_version
audit_vars=vars/${BENCHMARK}.yml

# Set variable for format output
if [ -z $FORMAT ]; then
if [ -z "$FORMAT" ]; then
export format="json"
else
export format=$FORMAT
fi

# Set variable for autogroup
if [ -z $GROUP ]; then
export auto_group="ungrouped"
if [ -z "$GROUP" ]; then
export host_auto_group="ungrouped"
else
export auto_group=$GROUP
export host_auto_group=$GROUP
fi

# set default variable for varfile_path
if [ -z "$VARS_PATH" ]; then
export varfile_path=$audit_content_dir/$audit_vars
else
# Check -v exists fail if not
if [ -f "$VARS_PATH" ]; then
export varfile_path=$VARS_PATH
else
echo "passed option '-v' $VARS_PATH does not exist"
exit 1
fi
export varfile_path=$audit_content_dir/$audit_vars
else
# Check -v exists fail if not
if [ -f "$VARS_PATH" ]; then
export varfile_path=$VARS_PATH
else
echo "passed option '-v' $VARS_PATH does not exist"
exit 1
fi
fi


## System variables captured for metadata

host_machine_uuid=`if [ ! -z /sys/class/dmi/id/product_uuid ]; then cat /sys/class/dmi/id/product_uuid; else dmidecode -s system-uuid; fi`
host_epoch=`date +%s`
host_os_locale=`date +%Z`
host_os_name=`grep "^NAME=" /etc/os-release | cut -d '"' -f2 | sed 's/ //' | cut -d ' ' -f1`
host_os_version=`grep "^VERSION_ID=" /etc/os-release | cut -d '"' -f2`
host_os_hostname=`hostname`
host_machine_uuid="$(if [ -f /sys/class/dmi/id/product_uuid ]; then cat /sys/class/dmi/id/product_uuid; else dmidecode -s system-uuid; fi)"
host_epoch="$(date +%s)"
host_os_locale="$(date +%Z)"
host_os_name="$(grep "^NAME=" /etc/os-release | cut -d '"' -f2 | sed 's/ //' | cut -d' ' -f1)"
host_os_version="$(grep "^VERSION_ID=" /etc/os-release | cut -d '"' -f2)"
host_os_hostname="$(hostname)"

## Set variable audit_out
if [ -z $OUTFILE ]; then
export audit_out=$AUDIT_CONTENT_LOCATION/audit_${host_os_hostname}-${BENCHMARK}-${BENCHMARK_OS}_${host_epoch}.$format
if [ -z "$OUTFILE" ]; then
export audit_out=${AUDIT_CONTENT_LOCATION}/audit_${host_os_hostname}-${BENCHMARK}-${BENCHMARK_OS}_${host_epoch}.$format
else
export audit_out=$OUTFILE
export audit_out=${OUTFILE}
fi


## Set the AUDIT json string
audit_json_vars='{"benchmark_type":"'"$BENCHMARK"'","benchmark_os":"'"$BENCHMARK_OS"'","benchmark_version":"'"$BENCHMARK_VER"'","machine_uuid":"'"$host_machine_uuid"'","epoch":"'"$host_epoch"'","os_locale":"'"$host_os_locale"'","os_release":"'"$host_os_version"'","os_distribution":"'"$host_os_name"'","os_hostname":"'"$host_os_hostname"'","auto_group":"'"$host_auto_group"'","system_type":"'"$host_system_type"'"}'
audit_json_vars='{"benchmark_type":'"$BENCHMARK"'","benchmark_os":"'"$BENCHMARK_OS"'","benchmark_version":"'"$BENCHMARK_VER"'","machine_uuid":"'"$host_machine_uuid"'","epoch":"'"$host_epoch"'","os_locale":"'"$host_os_locale"'","os_release":"'"$host_os_version"'","os_distribution":"'"$host_os_name"'","os_hostname":"'"$host_os_hostname"'","auto_group":"'"$host_auto_group"'","system_type":"'"$host_system_type"'"}'

## Run pre checks

Expand All @@ -146,46 +144,64 @@ echo "## Pre-Checks Start"
echo

export FAILURE=0
if [ -s "$AUDIT_BIN" ]; then
echo "OK Audit binary $AUDIT_BIN is available"
if [ -s "${AUDIT_BIN}" ]; then
echo "OK - Audit binary $AUDIT_BIN is available"
goss_installed_version="$($AUDIT_BIN -v | awk '{print $NF}' | cut -dv -f2)"
ver_calc=$(awk 'BEGIN{print $goss_installed_version < $AUDIT_BIN_MIN_VER}')
if [ $AUDIT_BIN_MIN_VER = "$goss_installed_version" ] || [ "$ver_calc" = 1 ] ; then
echo "OK - Goss is installed and Version is ok";
else
echo "WARNING - Goss installed = ${goss_installed_version}, does not met minimum of ${AUDIT_BIN_MIN_VER}"; export FAILURE=2
fi
else
echo "WARNING - The audit binary is not available at $AUDIT_BIN "; export FAILURE=1
echo "WARNING - The audit binary is not available at $AUDIT_BIN "; export FAILURE=1
fi

if [ -f "$audit_content_dir/$AUDIT_FILE" ]; then
echo "OK $audit_content_dir/$AUDIT_FILE is available"
if [ -f "${audit_content_dir}/${AUDIT_FILE}" ]; then
echo "OK - ${audit_content_dir}/${AUDIT_FILE} is available"
else
echo "WARNING - the $audit_content_dir/$AUDIT_FILE is not available"; export FAILURE=2
echo "WARNING - the $audit_content_dir/$AUDIT_FILE is not available"; export FAILURE=3
fi


if [ `echo $FAILURE` != 0 ]; then
echo "## Pre-checks failed please see output"
exit 1
if [ "${FAILURE}" != 0 ]; then
echo "## Pre-checks failed please see output"
exit 1
else
echo
echo "## Pre-checks Successful"
echo
echo
echo "## Pre-checks Successful"
echo
fi

# format output types
# json, rspecish = grep -A 4 \"summary\": $audit_out
# tap junit no output as no summary
# documentation = tail -2 $audit_out

# defaults
output_summary="tail -2 $audit_out"
format_output="-f $format"

if [ "$format" = json ]; then
format_output="-f json -o pretty"
output_summary='grep -A 4 \"summary\": $audit_out'
elif [ "$format" = junit ] || [ "$format" = tap ]; then
output_summary=""
fi

## Run commands
echo "#############"
echo "Audit Started"
echo "#############"
echo
$AUDIT_BIN -g $audit_content_dir/$AUDIT_FILE --vars $varfile_path --vars-inline $audit_json_vars v -f $format -o pretty > $audit_out
$AUDIT_BIN -g "$audit_content_dir/$AUDIT_FILE" --vars "$varfile_path" --vars-inline "$audit_json_vars" v $format_output > "$audit_out"

# create screen output
if [ `grep -c $BENCHMARK $audit_out` != 0 ]; then
echo "
`tail -7 $audit_out`
Completed file can be found at $audit_out"
echo "###############"
echo "Audit Completed"
echo "###############"

if [ "$(grep -c $BENCHMARK "$audit_out")" != 0 ] || [ "$format" = junit ] || [ "$format" = tap ]; then
eval $output_summary
echo " Completed file can be found at $audit_out"
echo "###############"
echo "Audit Completed"
echo "###############"
else
echo "Fail Audit - There were issues when running the audit please investigate $audit_out"
echo -e "Fail: There were issues when running the audit please investigate $audit_out"
fi

0 comments on commit 45dbfb8

Please sign in to comment.