Compare commits

...

6 Commits

Author SHA1 Message Date
861ad71734 chore: rename some scripts
- password configuration related scripts : ensure they start as "password_" like others checks
2025-07-11 15:33:53 +02:00
68f629ed36 adding new scripts for debian12
- "users_homedir_is_configured.sh" is a concatenation of different existing scripts:
        - [users_homedir_exist.sh](https://github.com/ovh/debian-cis/blob/master/bin/hardening/users_homedir_exist.sh)
        - [users_homedir_ownership.sh](https://github.com/ovh/debian-cis/blob/master/bin/hardening/users_homedir_ownership.sh)
        - [check_user_dir_perm.sh](https://github.com/ovh/debian-cis/blob/master/bin/hardening/check_user_dir_perm.sh)
And so is its test
It will be mapped as 7.2.9 for debian 12

- The following scripts are a split from [5.3.1_enable_pwquality.sh](https://github.com/ovh/debian-cis/blob/master/bin/hardening/enable_pwquality.sh):
        - enable_libpam_pwquality.sh    -> will be mapped as 5.3.2.3
        - install_libpam_pwquality.sh   -> will be mapped as 5.3.1.3
        - password_complexity.sh        -> will be mapped as 5.3.3.2.3
        - password_min_length.sh        -> will be mapped as 5.3.3.2.2

The others are scripts are new.
They will be mapped as follow for debian 12 CIS :

- apt_gpg_is_configured.sh                      -> 1.2.1.1
- dev_shm_separate_partition.sh                 -> 1.2.2.1
- install_iptables.sh                           -> 4.3.1.1
- install_nftables.sh                           -> 4.2.1
- password_consecutive_characters.sh            -> 5.3.3.2.4
- password_max_sequential_characters.sh         -> 5.3.3.2.5
2025-07-11 15:33:46 +02:00
51bc5825d6 refactor: is_kernel_option_enabled (#267)
Current "is_kernel_option_enabled" function is doing many things, like checking for a kernel option AND checking a kernel module state AND checking if it is disabled
We split it in different functions:
        - is_kernel_monolithic
        - is_kernel_option_enabled -> check for a kernel configuration in the running kernel
        - is_kernel_module_loaded -> check if a module is currently loaded
        - is_kernel_module_available -> check if a module is configured in all available kernel configs
        - is_kernel_module_disabled   -> check if a kernel module is disabled in the modprobe configuration

Also:

- update its behaviour to debian 12 CIS recommendation, to check if a module is "available in ANY installed kernel"
- fix "disable_usb_storage" to look for correct module name once loaded : issue #249
- the associated checks now check separately if the module is loaded, and if it is configured
- for checks about kernel module presence, the "apply" function now manages to disable the module in the modprobe configuration (if kernel not monolithic) (but still wont unload it)

Co-authored-by: Damien Cavagnini <damien.cavagnini@corp.ovh.com>
2025-07-11 11:20:59 +02:00
ab0dba9f95 chore: drop debian 10 and below support (#264)
Currently, the only LTS Debian are 11 and 12
We only support CIS for LTS debian

Co-authored-by: Damien Cavagnini <damien.cavagnini@corp.ovh.com>
2025-07-04 14:18:56 +02:00
f2c6f36b94 fix: ipv6_is_enabled related checks (#263)
fix issue #251 : https://github.com/ovh/debian-cis/issues/251

the 'is_ipv6_enabled' function was doing some 'crit' actions, which is not the expected behaviour: we don't want to fail if ipv6 is enabled, it is just an infor that checks are going to use.

Also, it was overriding the SYSCTL_PARAMS that could have been defined in the checks.

Co-authored-by: Damien Cavagnini <damien.cavagnini@corp.ovh.com>
2025-07-04 09:08:50 +02:00
6123a56653 fix: update record_mac_edit.sh to use apparmor instead of selinux (#262)
Update record_mac_edit.sh to be compliant with debian11 and debian12 CIS recommendations.

fix issue #195

Co-authored-by: Damien Cavagnini <damien.cavagnini@corp.ovh.com>
2025-07-03 09:27:09 +02:00
61 changed files with 1844 additions and 387 deletions

View File

@ -4,13 +4,6 @@ on:
- pull_request
- push
jobs:
functionnal-tests-docker-debian10:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Run the tests debian10
run: ./tests/docker_build_and_run_tests.sh debian10
functionnal-tests-docker-debian11:
runs-on: ubuntu-latest
steps:

View File

@ -4,7 +4,7 @@
# NAME
cis-hardening - CIS Debian 10/11/12 Hardening
cis-hardening - CIS Debian 11/12 Hardening
# SYNOPSIS
@ -12,7 +12,7 @@ cis-hardening - CIS Debian 10/11/12 Hardening
# DESCRIPTION
Modular Debian 10/11/12 security hardening scripts based on the CIS (https://www.cisecurity.org) recommendations.
Modular Debian 11/12 security hardening scripts based on the CIS (https://www.cisecurity.org) recommendations.
We use it at OVHcloud (https://www.ovhcloud.com) to harden our PCI-DSS infrastructure.

View File

@ -1,4 +1,4 @@
# :lock: CIS Debian 10/11/12 Hardening
# :lock: CIS Debian 11/12 Hardening
<p align="center">
@ -13,7 +13,7 @@
![License](https://img.shields.io/github/license/ovh/debian-cis)
---
Modular Debian 10/11/12 security hardening scripts based on [cisecurity.org](https://www.cisecurity.org)
Modular Debian 11/12 security hardening scripts based on [cisecurity.org](https://www.cisecurity.org)
recommendations. We use it at [OVHcloud](https://www.ovhcloud.com) to harden our PCI-DSS infrastructure.
NB : Although Debian 12 CIS Hardening guide is still in development, we do use this set of scripts
@ -174,7 +174,7 @@ Functional tests are available. They are to be run in a Docker environment.
$ ./tests/docker_build_and_run_tests.sh <target> [name of test script...]
```
With `target` being like `debian10` or `debian11`.
With `target` being like `debian11` or `debian12`.
Running without script arguments will run all tests in `./tests/hardening/` directory.
Or you can specify one or several test script to be run.

View File

@ -254,7 +254,7 @@ if [ "$DISTRIBUTION" != "debian" ]; then
echo "You can deactivate this message by setting the LOGLEVEL variable in /etc/hardening.cfg"
fi
else
if [ "$DEB_MAJ_VER" = "sid" ] || [ "$DEB_MAJ_VER" -gt "$HIGHEST_SUPPORTED_DEBIAN_VERSION" ]; then
if [ "$DEB_MAJ_VER" -gt "$HIGHEST_SUPPORTED_DEBIAN_VERSION" ]; then
echo "Your debian version is too recent and is not supported yet because there is no official CIS PDF for this version yet."
if [ "$ALLOW_UNSUPPORTED_DISTRIBUTION" -eq 0 ]; then
echo "If you want to run it anyway, you can use the flag --allow-unsupported-distribution"

View File

@ -59,17 +59,9 @@ check_config() {
:
}
# As we use DEB_MAJ_VER, which is set by constants.sh, itself sourced by main.sh below,
# We need to call this in the subs called by main.sh when it is sourced, otherwise it would
# either be too soon (DEB_MAJ_VER not defined) or too late (test has already been run)
_set_vars_jit() {
if [ "$DEB_MAJ_VER" = "sid" ] || [ "$DEB_MAJ_VER" -ge "11" ]; then
CONF_LINE_REGEX="ENCRYPT_METHOD (SHA512|yescrypt|YESCRYPT)"
CONF_LINE="ENCRYPT_METHOD YESCRYPT"
else
CONF_LINE_REGEX="ENCRYPT_METHOD SHA512"
CONF_LINE="ENCRYPT_METHOD SHA512"
fi
CONF_LINE_REGEX="ENCRYPT_METHOD (SHA512|yescrypt|YESCRYPT)"
CONF_LINE="ENCRYPT_METHOD YESCRYPT"
}
# Source Root Dir Parameter

View File

@ -49,11 +49,7 @@ apply() {
ok "$CONF_LINE is present in $CONF_FILE"
else
warn "$CONF_LINE is not present in $CONF_FILE"
if [ "$DEB_MAJ_VER" = "sid" ] || [ "$DEB_MAJ_VER" -ge "11" ]; then
add_line_file_before_pattern "$CONF_FILE" "password [success=1 default=ignore] pam_unix.so yescrypt" "# pam-auth-update(8) for details."
else
add_line_file_before_pattern "$CONF_FILE" "password [success=1 default=ignore] pam_unix.so sha512" "# pam-auth-update(8) for details."
fi
add_line_file_before_pattern "$CONF_FILE" "password [success=1 default=ignore] pam_unix.so yescrypt" "# pam-auth-update(8) for details."
fi
fi
}
@ -67,11 +63,7 @@ check_config() {
# We need to call this in the subs called by main.sh when it is sourced, otherwise it would
# either be too soon (DEB_MAJ_VER not defined) or too late (test has already been run)
_set_vars_jit() {
if [ "$DEB_MAJ_VER" = "sid" ] || [ "$DEB_MAJ_VER" -ge "11" ]; then
CONF_LINE="^\s*password\s.+\s+pam_unix\.so\s+.*(sha512|yescrypt)" # https://github.com/ovh/debian-cis/issues/158
else
CONF_LINE="^\s*password\s.+\s+pam_unix\.so\s+.*sha512"
fi
CONF_LINE="^\s*password\s.+\s+pam_unix\.so\s+.*(sha512|yescrypt)" # https://github.com/ovh/debian-cis/issues/158
}
# Source Root Dir Parameter

View File

@ -37,7 +37,7 @@ audit() {
pw_found+="$user "
ok "User $user has a disabled password."
# yescrypt: Check password against $y$<salt>$<base64>
elif [ "$DEB_MAJ_VER" -ge "11" ] && [[ $passwd =~ ^\$y\$[./A-Za-z0-9]+\$[./A-Za-z0-9]{,86}\$[./A-Za-z0-9]{43} ]]; then
elif [[ $passwd =~ ^\$y\$[./A-Za-z0-9]+\$[./A-Za-z0-9]{,86}\$[./A-Za-z0-9]{43} ]]; then
pw_found+="$user "
ok "User $user has suitable yescrypt hashed password."
# sha512: Check password against $6$<salt>$<base64>, see `man 3 crypt`
@ -46,11 +46,7 @@ audit() {
ok "User $user has suitable sha512crypt hashed password."
else
pw_found+="$user "
if [ "$DEB_MAJ_VER" -ge "11" ]; then
crit "User $user has a password that is not sha512crypt nor yescrypt hashed."
else
crit "User $user has a password that is not sha512crypt hashed."
fi
crit "User $user has a password that is not sha512crypt nor yescrypt hashed."
fi
done
if [[ -z "$users_reviewed" ]]; then

View File

@ -0,0 +1,105 @@
#!/bin/bash
# run-shellcheck
#
# CIS Debian Hardening
#
#
# Ensure GPG keys are configured (Manual)
#
set -e # One error, it's over
set -u # One variable unset, it's over
# shellcheck disable=2034
HARDENING_LEVEL=3
# shellcheck disable=2034
DESCRIPTION="Ensure GPG keys are configured"
APT_KEY_PATH="/etc/apt/trusted.gpg.d"
APT_KEY_FILE="/etc/apt/trusted.gpg"
# from "man apt-secure"
SOURCES_UNSECURE_OPTION='allow-insecure=yes'
APT_UNSECURE_OPTION='Acquire::AllowInsecureRepositories=true'
# This function will be called if the script status is on enabled / audit mode
audit() {
key_files=0
info "Verifying that apt keys are present"
# apt-key list requires that gnupg2 is installed
# we are not going to install it for the sake of a test, so we only check the presence of key files
is_file_empty "$APT_KEY_FILE"
if [ "$FNRET" -eq 1 ]; then
info "$APT_KEY_FILE present and not empty"
key_files=$((key_files + 1))
fi
does_file_exist "$APT_KEY_PATH"
if [ "$FNRET" -ne 0 ]; then
info "$APT_KEY_PATH is missing"
else
asc_files=$(find "$APT_KEY_PATH" -name '*.asc' | wc -l)
key_files=$((key_files + asc_files))
gpg_files=$(find "$APT_KEY_PATH" -name '*.gpg' | wc -l)
key_files=$((key_files + gpg_files))
if [ "$asc_files" -eq 0 ] && [ "$gpg_files" -eq 0 ]; then
info "No key found in $APT_KEY_PATH"
fi
fi
if [ "$key_files" -eq 0 ]; then
crit "No GPG file found"
else
# we do not test the GPG keys validity, but we ensure we don't bypass them
info "Ensure an unsecure option is not set in some sources list"
unsecure_sources=$(find /etc/apt/ -name '*.list' -exec grep -l "$SOURCES_UNSECURE_OPTION" {} \;)
if [ -n "$unsecure_sources" ]; then
crit "Some source files use $SOURCES_UNSECURE_OPTION : $unsecure_sources"
fi
info "Ensure an unsecure option is not set in some apt configuration"
unsecure_option=$(grep -R "$APT_UNSECURE_OPTION" /etc/apt | wc -l)
if [ "$unsecure_option" -gt 0 ]; then
crit "$APT_UNSECURE_OPTION is set in apt configuration"
fi
fi
}
# This function will be called if the script status is on enabled mode
apply() {
audit
if [ "$FNRET" -gt 0 ]; then
crit "Your configuraiton does not match the recommendation. Please fix it manually"
else
info "Nothing to apply"
fi
}
# This function will check config parameters required
check_config() {
# No parameter for this script
:
}
# Source Root Dir Parameter
if [ -r /etc/default/cis-hardening ]; then
# shellcheck source=../../debian/default
. /etc/default/cis-hardening
fi
if [ -z "$CIS_LIB_DIR" ]; then
echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment."
echo "Cannot source CIS_LIB_DIR variable, aborting."
exit 128
fi
# Main function, will call the proper functions given the configuration (audit, enabled, disabled)
if [ -r "${CIS_LIB_DIR}"/main.sh ]; then
# shellcheck source=../../lib/main.sh
. "${CIS_LIB_DIR}"/main.sh
else
echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening"
exit 128
fi

View File

@ -6,7 +6,7 @@
#
#
# Ensure that the distribution version is debian and that the version is 9 or 10
# Ensure that the distribution version is debian and supported
#
set -e # One error, it's over
@ -22,7 +22,7 @@ audit() {
if [ "$DISTRIBUTION" != "debian" ]; then
crit "Your distribution has been identified as $DISTRIBUTION which is not debian"
else
if [ "$DEB_MAJ_VER" = "sid" ] || [ "$DEB_MAJ_VER" -gt "$HIGHEST_SUPPORTED_DEBIAN_VERSION" ]; then
if [ "$DEB_MAJ_VER" -gt "$HIGHEST_SUPPORTED_DEBIAN_VERSION" ]; then
crit "Your distribution is too recent and is not yet supported."
elif [ "$DEB_MAJ_VER" -lt "$SMALLEST_SUPPORTED_DEBIAN_VERSION" ]; then
crit "Your distribution is debian but is deprecated. Consider upgrading to a supported version."

View File

@ -0,0 +1,80 @@
#!/bin/bash
# run-shellcheck
#
# CIS Debian Hardening
#
#
# Ensure /dev/shm is a separate partition (Automated)
#
set -e # One error, it's over
set -u # One variable unset, it's over
# shellcheck disable=2034
HARDENING_LEVEL=3
# shellcheck disable=2034
DESCRIPTION="Ensure /dev/shm is a separate partition"
# Quick factoring as many script use the same logic
PARTITION="/dev/shm"
# This function will be called if the script status is on enabled / audit mode
audit() {
info "Verifying that $PARTITION is a partition"
FNRET=0
is_a_partition "$PARTITION"
if [ "$FNRET" -gt 0 ]; then
crit "$PARTITION is not a partition"
FNRET=2
else
ok "$PARTITION is a partition"
is_mounted "$PARTITION"
if [ "$FNRET" -gt 0 ]; then
warn "$PARTITION is not mounted"
FNRET=1
else
ok "$PARTITION is mounted"
fi
fi
}
# This function will be called if the script status is on enabled mode
apply() {
audit
if [ "$FNRET" = 0 ]; then
ok "$PARTITION is correctly set"
elif [ "$FNRET" = 2 ]; then
crit "$PARTITION is not a partition, correct this by yourself, I cannot help you here"
else
info "mounting $PARTITION"
mount "$PARTITION"
fi
}
# This function will check config parameters required
check_config() {
# No parameter for this script
:
}
# Source Root Dir Parameter
if [ -r /etc/default/cis-hardening ]; then
# shellcheck source=../../debian/default
. /etc/default/cis-hardening
fi
if [ -z "$CIS_LIB_DIR" ]; then
echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment."
echo "Cannot source CIS_LIB_DIR variable, aborting."
exit 128
fi
# Main function, will call the proper functions given the configuration (audit, enabled, disabled)
if [ -r "${CIS_LIB_DIR}"/main.sh ]; then
# shellcheck source=../../lib/main.sh
. "${CIS_LIB_DIR}"/main.sh
else
echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening"
exit 128
fi

View File

@ -26,11 +26,25 @@ audit() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing or disable this check!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is enabled!"
is_kernel_module_loaded "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is loaded!"
else
ok "$MODULE_NAME is disabled"
ok "$MODULE_NAME is not loaded"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then
ok "$MODULE_NAME is disabled in the modprobe configuration"
else
is_kernel_module_available "$KERNEL_OPTION"
if [ "$FNRET" -eq 0 ]; then
crit "$MODULE_NAME is available in some kernel config, but not disabled"
else
ok "$MODULE_NAME is not available in any kernel config"
fi
fi
fi
fi
}
@ -41,11 +55,18 @@ apply() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
warn "I cannot fix $MODULE_NAME, recompile your kernel or blacklist module $MODULE_NAME (/etc/modprobe.d/blacklist.conf : +install $MODULE_NAME /bin/true)"
else
ok "$MODULE_NAME is disabled"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
warn "I wont unload the module, unload it manually or recompile the kernel if needed"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 1 ]; then
echo "install $MODULE_NAME /bin/true" >>/etc/modprobe.d/"$MODULE_NAME".conf
info "$MODULE_NAME has been disabled in the modprobe configuration"
fi
fi
fi
}

View File

@ -28,11 +28,25 @@ audit() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing or disable this check!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is enabled!"
is_kernel_module_loaded "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is loaded!"
else
ok "$MODULE_NAME is disabled"
ok "$MODULE_NAME is not loaded"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then
ok "$MODULE_NAME is disabled in the modprobe configuration"
else
is_kernel_module_available "$KERNEL_OPTION"
if [ "$FNRET" -eq 0 ]; then
crit "$MODULE_NAME is available in some kernel config, but not disabled"
else
ok "$MODULE_NAME is not available in any kernel config"
fi
fi
fi
fi
}
@ -43,11 +57,18 @@ apply() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
warn "I cannot fix $MODULE_NAME, recompile your kernel or blacklist module $MODULE_NAME (/etc/modprobe.d/blacklist.conf : +install $MODULE_NAME /bin/true)"
else
ok "$MODULE_NAME is disabled"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
warn "I wont unload the module, unload it manually or recompile the kernel if needed"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 1 ]; then
echo "install $MODULE_NAME /bin/true" >>/etc/modprobe.d/"$MODULE_NAME".conf
info "$MODULE_NAME has been disabled in the modprobe configuration"
fi
fi
fi
}

View File

@ -26,11 +26,25 @@ audit() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing or disable this check!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is enabled!"
is_kernel_module_loaded "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is loaded!"
else
ok "$MODULE_NAME is disabled"
ok "$MODULE_NAME is not loaded"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then
ok "$MODULE_NAME is disabled in the modprobe configuration"
else
is_kernel_module_available "$KERNEL_OPTION"
if [ "$FNRET" -eq 0 ]; then
crit "$MODULE_NAME is available in some kernel config, but not disabled"
else
ok "$MODULE_NAME is not available in any kernel config"
fi
fi
fi
fi
}
@ -41,11 +55,18 @@ apply() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
warn "I cannot fix $MODULE_NAME, recompile your kernel or blacklist module $MODULE_NAME (/etc/modprobe.d/blacklist.conf : +install $MODULE_NAME /bin/true)"
else
ok "$MODULE_NAME is disabled"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
warn "I wont unload the module, unload it manually or recompile the kernel if needed"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 1 ]; then
echo "install $MODULE_NAME /bin/true" >>/etc/modprobe.d/"$MODULE_NAME".conf
info "$MODULE_NAME has been disabled in the modprobe configuration"
fi
fi
fi
}

View File

@ -26,11 +26,25 @@ audit() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing or disable this check!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is enabled!"
is_kernel_module_loaded "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is loaded!"
else
ok "$MODULE_NAME is disabled"
ok "$MODULE_NAME is not loaded"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then
ok "$MODULE_NAME is disabled in the modprobe configuration"
else
is_kernel_module_available "$KERNEL_OPTION"
if [ "$FNRET" -eq 0 ]; then
crit "$MODULE_NAME is available in some kernel config, but not disabled"
else
ok "$MODULE_NAME is not available in any kernel config"
fi
fi
fi
fi
}
@ -41,11 +55,18 @@ apply() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
warn "I cannot fix $MODULE_NAME, recompile your kernel or blacklist module $MODULE_NAME (/etc/modprobe.d/blacklist.conf : +install $MODULE_NAME /bin/true)"
else
ok "$MODULE_NAME is disabled"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
warn "I wont unload the module, unload it manually or recompile the kernel if needed"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 1 ]; then
echo "install $MODULE_NAME /bin/true" >>/etc/modprobe.d/"$MODULE_NAME".conf
info "$MODULE_NAME has been disabled in the modprobe configuration"
fi
fi
fi
}

View File

@ -26,11 +26,25 @@ audit() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing or disable this check!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is enabled!"
is_kernel_module_loaded "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is loaded!"
else
ok "$MODULE_NAME is disabled"
ok "$MODULE_NAME is not loaded"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then
ok "$MODULE_NAME is disabled in the modprobe configuration"
else
is_kernel_module_available "$KERNEL_OPTION"
if [ "$FNRET" -eq 0 ]; then
crit "$MODULE_NAME is available in some kernel config, but not disabled"
else
ok "$MODULE_NAME is not available in any kernel config"
fi
fi
fi
fi
}
@ -41,11 +55,18 @@ apply() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
warn "I cannot fix $MODULE_NAME, recompile your kernel or blacklist module $MODULE_NAME (/etc/modprobe.d/blacklist.conf : +install $MODULE_NAME /bin/true)"
else
ok "$MODULE_NAME is disabled"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
warn "I wont unload the module, unload it manually or recompile the kernel if needed"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 1 ]; then
echo "install $MODULE_NAME /bin/true" >>/etc/modprobe.d/"$MODULE_NAME".conf
info "$MODULE_NAME has been disabled in the modprobe configuration"
fi
fi
fi
}

View File

@ -26,11 +26,25 @@ audit() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing or disable this check!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is enabled!"
is_kernel_module_loaded "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is loaded!"
else
ok "$MODULE_NAME is disabled"
ok "$MODULE_NAME is not loaded"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then
ok "$MODULE_NAME is disabled in the modprobe configuration"
else
is_kernel_module_available "$KERNEL_OPTION"
if [ "$FNRET" -eq 0 ]; then
crit "$MODULE_NAME is available in some kernel config, but not disabled"
else
ok "$MODULE_NAME is not available in any kernel config"
fi
fi
fi
fi
}
@ -41,11 +55,18 @@ apply() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
warn "I cannot fix $MODULE_NAME, recompile your kernel or blacklist module $MODULE_NAME (/etc/modprobe.d/blacklist.conf : +install $MODULE_NAME /bin/true)"
else
ok "$MODULE_NAME is disabled"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
warn "I wont unload the module, unload it manually or recompile the kernel if needed"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 1 ]; then
echo "install $MODULE_NAME /bin/true" >>/etc/modprobe.d/"$MODULE_NAME".conf
info "$MODULE_NAME has been disabled in the modprobe configuration"
fi
fi
fi
}

View File

@ -28,11 +28,25 @@ audit() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing or disable this check!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is enabled!"
is_kernel_module_loaded "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is loaded!"
else
ok "$MODULE_NAME is disabled"
ok "$MODULE_NAME is not loaded"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then
ok "$MODULE_NAME is disabled in the modprobe configuration"
else
is_kernel_module_available "$KERNEL_OPTION"
if [ "$FNRET" -eq 0 ]; then
crit "$MODULE_NAME is available in some kernel config, but not disabled"
else
ok "$MODULE_NAME is not available in any kernel config"
fi
fi
fi
fi
}
@ -43,11 +57,18 @@ apply() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
warn "I cannot fix $MODULE_NAME, recompile your kernel or blacklist module $MODULE_NAME (/etc/modprobe.d/blacklist.conf : +install $MODULE_NAME /bin/true)"
else
ok "$MODULE_NAME is disabled"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
warn "I wont unload the module, unload it manually or recompile the kernel if needed"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 1 ]; then
echo "install $MODULE_NAME /bin/true" >>/etc/modprobe.d/"$MODULE_NAME".conf
info "$MODULE_NAME has been disabled in the modprobe configuration"
fi
fi
fi
}

View File

@ -28,11 +28,25 @@ audit() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing or disable this check!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is enabled!"
is_kernel_module_loaded "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is loaded!"
else
ok "$MODULE_NAME is disabled"
ok "$MODULE_NAME is not loaded"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then
ok "$MODULE_NAME is disabled in the modprobe configuration"
else
is_kernel_module_available "$KERNEL_OPTION"
if [ "$FNRET" -eq 0 ]; then
crit "$MODULE_NAME is available in some kernel config, but not disabled"
else
ok "$MODULE_NAME is not available in any kernel config"
fi
fi
fi
fi
}
@ -43,11 +57,18 @@ apply() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
warn "I cannot fix $MODULE_NAME, recompile your kernel or blacklist module $MODULE_NAME (/etc/modprobe.d/blacklist.conf : +install $MODULE_NAME /bin/true)"
else
ok "$MODULE_NAME is disabled"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
warn "I wont unload the module, unload it manually or recompile the kernel if needed"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 1 ]; then
echo "install $MODULE_NAME /bin/true" >>/etc/modprobe.d/"$MODULE_NAME".conf
info "$MODULE_NAME has been disabled in the modprobe configuration"
fi
fi
fi
}

View File

@ -26,11 +26,25 @@ audit() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing or disable this check!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is enabled!"
is_kernel_module_loaded "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is loaded!"
else
ok "$MODULE_NAME is disabled"
ok "$MODULE_NAME is not loaded"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then
ok "$MODULE_NAME is disabled in the modprobe configuration"
else
is_kernel_module_available "$KERNEL_OPTION"
if [ "$FNRET" -eq 0 ]; then
crit "$MODULE_NAME is available in some kernel config, but not disabled"
else
ok "$MODULE_NAME is not available in any kernel config"
fi
fi
fi
fi
}
@ -41,11 +55,18 @@ apply() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
warn "I cannot fix $MODULE_NAME, recompile your kernel or blacklist module $MODULE_NAME (/etc/modprobe.d/blacklist.conf : +install $MODULE_NAME /bin/true)"
else
ok "$MODULE_NAME is disabled"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
warn "I wont unload the module, unload it manually or recompile the kernel if needed"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 1 ]; then
echo "install $MODULE_NAME /bin/true" >>/etc/modprobe.d/"$MODULE_NAME".conf
info "$MODULE_NAME has been disabled in the modprobe configuration"
fi
fi
fi
}

View File

@ -28,11 +28,25 @@ audit() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing or disable this check!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is enabled!"
is_kernel_module_loaded "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is loaded!"
else
ok "$MODULE_NAME is disabled"
ok "$MODULE_NAME is not loaded"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then
ok "$MODULE_NAME is disabled in the modprobe configuration"
else
is_kernel_module_available "$KERNEL_OPTION"
if [ "$FNRET" -eq 0 ]; then
crit "$MODULE_NAME is available in some kernel config, but not disabled"
else
ok "$MODULE_NAME is not available in any kernel config"
fi
fi
fi
fi
}
@ -43,11 +57,18 @@ apply() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
warn "I cannot fix $MODULE_NAME, recompile your kernel or blacklist module $MODULE_NAME (/etc/modprobe.d/blacklist.conf : +install $MODULE_NAME /bin/true)"
else
ok "$MODULE_NAME is disabled"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
warn "I wont unload the module, unload it manually or recompile the kernel if needed"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 1 ]; then
echo "install $MODULE_NAME /bin/true" >>/etc/modprobe.d/"$MODULE_NAME".conf
info "$MODULE_NAME has been disabled in the modprobe configuration"
fi
fi
fi
}

View File

@ -26,11 +26,25 @@ audit() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing or disable this check!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is enabled!"
is_kernel_module_loaded "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is loaded!"
else
ok "$MODULE_NAME is disabled"
ok "$MODULE_NAME is not loaded"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then
ok "$MODULE_NAME is disabled in the modprobe configuration"
else
is_kernel_module_available "$KERNEL_OPTION"
if [ "$FNRET" -eq 0 ]; then
crit "$MODULE_NAME is available in some kernel config, but not disabled"
else
ok "$MODULE_NAME is not available in any kernel config"
fi
fi
fi
fi
}
@ -41,11 +55,18 @@ apply() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME" "($MODULE_NAME|install)"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
warn "I cannot fix $MODULE_NAME, recompile your kernel or blacklist module $MODULE_NAME (/etc/modprobe.d/blacklist.conf : +install $MODULE_NAME /bin/true)"
else
ok "$MODULE_NAME is disabled"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
warn "I wont unload the module, unload it manually or recompile the kernel if needed"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 1 ]; then
echo "install $MODULE_NAME /bin/true" >>/etc/modprobe.d/"$MODULE_NAME".conf
info "$MODULE_NAME has been disabled in the modprobe configuration"
fi
fi
fi
}

View File

@ -20,7 +20,10 @@ DESCRIPTION="Disable USB storage."
# Note: we check /proc/config.gz to be compliant with both monolithic and modular kernels
KERNEL_OPTION="CONFIG_USB_STORAGE"
# name as used for "modprobe"
MODULE_NAME="usb-storage"
# name as returned by "modinfo -F name <module_file.ko>"
LOADED_MODULE_NAME="usb_storage"
# This function will be called if the script status is on enabled / audit mode
audit() {
@ -28,11 +31,25 @@ audit() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing or disable this check!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
crit "$MODULE_NAME is enabled!"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
else
ok "$MODULE_NAME is disabled"
ok "$LOADED_MODULE_NAME is not loaded"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then
ok "$MODULE_NAME is disabled in the modprobe configuration"
else
is_kernel_module_available "$KERNEL_OPTION"
if [ "$FNRET" -eq 0 ]; then
crit "$MODULE_NAME is available in some kernel config, but not disabled"
else
ok "$MODULE_NAME is not available in any kernel config"
fi
fi
fi
fi
}
@ -43,11 +60,18 @@ apply() {
# In an unprivileged container, the kernel modules are host dependent, so you should consider enforcing it
ok "Container detected, consider host enforcing!"
else
is_kernel_option_enabled "$KERNEL_OPTION" "$MODULE_NAME"
if [ "$FNRET" = 0 ]; then # 0 means true in bash, so it IS activated
warn "I cannot fix $MODULE_NAME, recompile your kernel or blacklist module $MODULE_NAME (/etc/modprobe.d/blacklist.conf : +install $MODULE_NAME /bin/true)"
else
ok "$MODULE_NAME is disabled"
is_kernel_module_loaded "$KERNEL_OPTION" "$LOADED_MODULE_NAME"
if [ "$FNRET" -eq 0 ]; then # 0 means true in bash, so it IS activated
crit "$LOADED_MODULE_NAME is loaded!"
warn "I wont unload the module, unload it manually or recompile the kernel if needed"
fi
if [ "$IS_MONOLITHIC_KERNEL" -eq 1 ]; then
is_kernel_module_disabled "$MODULE_NAME"
if [ "$FNRET" -eq 1 ]; then
echo "install $MODULE_NAME /bin/true" >>/etc/modprobe.d/"$MODULE_NAME".conf
info "$MODULE_NAME has been disabled in the modprobe configuration"
fi
fi
fi
}

View File

@ -0,0 +1,67 @@
#!/bin/bash
# run-shellcheck
#
# CIS Debian Hardening
#
#
# Ensure pam_pwquality module is enabled (Automated)
#
set -e # One error, it's over
set -u # One variable unset, it's over
# shellcheck disable=2034
HARDENING_LEVEL=2
# shellcheck disable=2034
DESCRIPTION="Ensure pam_pwquality module is enabled."
PATTERN_COMMON='pam_pwquality.so'
FILE_COMMON='/etc/pam.d/common-password'
# This function will be called if the script status is on enabled / audit mode
audit() {
does_pattern_exist_in_file "$FILE_COMMON" "$PATTERN_COMMON"
if [ "$FNRET" = 0 ]; then
ok "$PATTERN_COMMON is present in $FILE_COMMON"
else
crit "$PATTERN_COMMON is not present in $FILE_COMMON"
fi
}
# This function will be called if the script status is on enabled mode
apply() {
does_pattern_exist_in_file $FILE_COMMON $PATTERN_COMMON
if [ "$FNRET" = 0 ]; then
ok "$PATTERN_COMMON is present in $FILE_COMMON"
else
warn "$PATTERN_COMMON is not present in $FILE_COMMON"
add_line_file_before_pattern "$FILE_COMMON" "password requisite pam_pwquality.so retry=3" "# pam-auth-update(8) for details."
fi
}
# This function will check config parameters required
check_config() {
:
}
# Source Root Dir Parameter
if [ -r /etc/default/cis-hardening ]; then
# shellcheck source=../../debian/default
. /etc/default/cis-hardening
fi
if [ -z "$CIS_LIB_DIR" ]; then
echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment."
echo "Cannot source CIS_LIB_DIR variable, aborting."
exit 128
fi
# Main function, will call the proper functions given the configuration (audit, enabled, disabled)
if [ -r "${CIS_LIB_DIR}"/main.sh ]; then
# shellcheck source=../../lib/main.sh
. "${CIS_LIB_DIR}"/main.sh
else
echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening"
exit 128
fi

View File

@ -59,23 +59,14 @@ apply() {
ok "$PATTERN_AUTH is present in $FILE_AUTH"
else
warn "$PATTERN_AUTH is not present in $FILE_AUTH, adding it"
if [ 10 -ge "$DEB_MAJ_VER" ]; then
add_line_file_before_pattern "$FILE_AUTH" "auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900" "# pam-auth-update(8) for details."
else
add_line_file_before_pattern "$FILE_AUTH" "auth required pam_faillock.so onerr=fail audit silent deny=5 unlock_time=900" "# pam-auth-update(8) for details."
fi
add_line_file_before_pattern "$FILE_AUTH" "auth required pam_faillock.so onerr=fail audit silent deny=5 unlock_time=900" "# pam-auth-update(8) for details."
fi
does_pattern_exist_in_file "$FILE_ACCOUNT" "$PATTERN_ACCOUNT"
if [ "$FNRET" = 0 ]; then
ok "$PATTERN_ACCOUNT is present in $FILE_ACCOUNT"
else
warn "$PATTERN_ACCOUNT is not present in $FILE_ACCOUNT, adding it"
if [ 10 -ge "$DEB_MAJ_VER" ]; then
add_line_file_before_pattern "$FILE_ACCOUNT" "account required pam_tally2.so" "# pam-auth-update(8) for details."
else
add_line_file_before_pattern "$FILE_ACCOUNT" "account required pam_faillock.so" "# pam-auth-update(8) for details."
fi
add_line_file_before_pattern "$FILE_ACCOUNT" "account required pam_faillock.so" "# pam-auth-update(8) for details."
fi
}

View File

@ -0,0 +1,78 @@
#!/bin/bash
# run-shellcheck
#
# CIS Debian Hardening
#
#
# Ensure iptables packages are installed (Automated)
#
set -e # One error, it's over
set -u # One variable unset, it's over
# shellcheck disable=2034
HARDENING_LEVEL=2
# shellcheck disable=2034
DESCRIPTION="Ensure iptables firewall is installed, does not check for its configuration."
# Note: CIS recommends your iptables rules to be persistent.
# Do as you want, but this script does not handle this
PACKAGES='iptables iptables-persistent'
# This function will be called if the script status is on enabled / audit mode
audit() {
FOUND=false
for PACKAGE in $PACKAGES; do
is_pkg_installed "$PACKAGE"
if [ "$FNRET" = 0 ]; then
ok "$PACKAGE provides firewalling feature"
FOUND=true
fi
done
if [ "$FOUND" = false ]; then
crit "None of the following firewall packages are installed: $PACKAGES"
fi
}
# This function will be called if the script status is on enabled mode
apply() {
for PACKAGE in $PACKAGES; do
is_pkg_installed "$PACKAGE"
if [ "$FNRET" = 0 ]; then
ok "$PACKAGE provides firewalling feature"
FOUND=true
fi
done
if [ "$FOUND" = false ]; then
crit "None of the following firewall packages are installed: $PACKAGES, installing them"
apt_install "$PACKAGES"
fi
}
# This function will check config parameters required
check_config() {
:
}
# Source Root Dir Parameter
if [ -r /etc/default/cis-hardening ]; then
# shellcheck source=../../debian/default
. /etc/default/cis-hardening
fi
if [ -z "$CIS_LIB_DIR" ]; then
echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment."
echo "Cannot source CIS_LIB_DIR variable, aborting."
exit 128
fi
# Main function, will call the proper functions given the configuration (audit, enabled, disabled)
if [ -r "${CIS_LIB_DIR}"/main.sh ]; then
# shellcheck source=../../lib/main.sh
. "${CIS_LIB_DIR}"/main.sh
else
echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening"
exit 128
fi

View File

@ -0,0 +1,66 @@
#!/bin/bash
# run-shellcheck
#
# CIS Debian Hardening
#
#
# Ensure libpam-pwquality is installed (Automated)
#
set -e # One error, it's over
set -u # One variable unset, it's over
# shellcheck disable=2034
HARDENING_LEVEL=2
# shellcheck disable=2034
DESCRIPTION="Ensure libpam-pwquality is installed "
PACKAGE='libpam-pwquality'
# This function will be called if the script status is on enabled / audit mode
audit() {
is_pkg_installed "$PACKAGE"
if [ "$FNRET" != 0 ]; then
crit "$PACKAGE is not installed!"
else
ok "$PACKAGE is installed"
fi
}
# This function will be called if the script status is on enabled mode
apply() {
is_pkg_installed "$PACKAGE"
if [ "$FNRET" = 0 ]; then
ok "$PACKAGE is installed"
else
crit "$PACKAGE is absent, installing it"
apt_install "$PACKAGE"
fi
}
# This function will check config parameters required
check_config() {
:
}
# Source Root Dir Parameter
if [ -r /etc/default/cis-hardening ]; then
# shellcheck source=../../debian/default
. /etc/default/cis-hardening
fi
if [ -z "$CIS_LIB_DIR" ]; then
echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment."
echo "Cannot source CIS_LIB_DIR variable, aborting."
exit 128
fi
# Main function, will call the proper functions given the configuration (audit, enabled, disabled)
if [ -r "${CIS_LIB_DIR}"/main.sh ]; then
# shellcheck source=../../lib/main.sh
. "${CIS_LIB_DIR}"/main.sh
else
echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening"
exit 128
fi

View File

@ -0,0 +1,78 @@
#!/bin/bash
# run-shellcheck
#
# CIS Debian Hardening
#
#
# Ensure nftables is installed (Automated)
#
set -e # One error, it's over
set -u # One variable unset, it's over
# shellcheck disable=2034
HARDENING_LEVEL=2
# shellcheck disable=2034
DESCRIPTION="Ensure nftables firewall is installed, does not check for its configuration."
# Note: CIS recommends your iptables rules to be persistent.
# Do as you want, but this script does not handle this
PACKAGES='nftables'
# This function will be called if the script status is on enabled / audit mode
audit() {
FOUND=false
for PACKAGE in $PACKAGES; do
is_pkg_installed "$PACKAGE"
if [ "$FNRET" = 0 ]; then
ok "$PACKAGE provides firewalling feature"
FOUND=true
fi
done
if [ "$FOUND" = false ]; then
crit "None of the following firewall packages are installed: $PACKAGES"
fi
}
# This function will be called if the script status is on enabled mode
apply() {
for PACKAGE in $PACKAGES; do
is_pkg_installed "$PACKAGE"
if [ "$FNRET" = 0 ]; then
ok "$PACKAGE provides firewalling feature"
FOUND=true
fi
done
if [ "$FOUND" = false ]; then
crit "None of the following firewall packages are installed: $PACKAGES, installing them"
apt_install "$PACKAGES"
fi
}
# This function will check config parameters required
check_config() {
:
}
# Source Root Dir Parameter
if [ -r /etc/default/cis-hardening ]; then
# shellcheck source=../../debian/default
. /etc/default/cis-hardening
fi
if [ -z "$CIS_LIB_DIR" ]; then
echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment."
echo "Cannot source CIS_LIB_DIR variable, aborting."
exit 128
fi
# Main function, will call the proper functions given the configuration (audit, enabled, disabled)
if [ -r "${CIS_LIB_DIR}"/main.sh ]; then
# shellcheck source=../../lib/main.sh
. "${CIS_LIB_DIR}"/main.sh
else
echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening"
exit 128
fi

View File

@ -0,0 +1,77 @@
#!/bin/bash
# run-shellcheck
#
# CIS Debian Hardening
#
#
# Ensure password complexity is configured (Manual)
#
set -e # One error, it's over
set -u # One variable unset, it's over
# shellcheck disable=2034
HARDENING_LEVEL=2
# shellcheck disable=2034
DESCRIPTION="Ensure password minimum length is configured "
OPTIONS=''
FILE_QUALITY='/etc/security/pwquality.conf'
# This function will be called if the script status is on enabled / audit mode
audit() {
for PW_OPT in $OPTIONS; do
PW_PARAM=$(echo "$PW_OPT" | cut -d= -f1)
PW_VALUE=$(echo "$PW_OPT" | cut -d= -f2)
# note : dont backslash regex characters, as 'does_pattern_exist_in_file' use "grep -E" which don't need it
PATTERN="${PW_PARAM}[[:space:]]?+=[[:space:]]?+$PW_VALUE"
does_pattern_exist_in_file "$FILE_QUALITY" "$PATTERN"
if [ "$FNRET" = 0 ]; then
ok "$PATTERN is present in $FILE_QUALITY"
else
crit "$PATTERN is not present in $FILE_QUALITY"
fi
done
}
# This function will be called if the script status is on enabled mode
apply() {
info "The values defined here should be adapted to one needs before applying."
}
# This function will create the config file for this check with default values
create_config() {
cat <<EOF
status=audit
# Put your custom configuration here
OPTIONS="minclass=3 dcredit=-1 ucredit=-2 ocredit=-1 lcredit=-1"
EOF
}
# This function will check config parameters required
check_config() {
:
}
# Source Root Dir Parameter
if [ -r /etc/default/cis-hardening ]; then
# shellcheck source=../../debian/default
. /etc/default/cis-hardening
fi
if [ -z "$CIS_LIB_DIR" ]; then
echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment."
echo "Cannot source CIS_LIB_DIR variable, aborting."
exit 128
fi
# Main function, will call the proper functions given the configuration (audit, enabled, disabled)
if [ -r "${CIS_LIB_DIR}"/main.sh ]; then
# shellcheck source=../../lib/main.sh
. "${CIS_LIB_DIR}"/main.sh
else
echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening"
exit 128
fi

View File

@ -0,0 +1,94 @@
#!/bin/bash
# run-shellcheck
#
# CIS Debian Hardening
#
#
# Ensure password same consecutive characters is configured (Automated)
#
set -e # One error, it's over
set -u # One variable unset, it's over
# shellcheck disable=2034
HARDENING_LEVEL=2
# shellcheck disable=2034
DESCRIPTION="Ensure password same consecutive characters is configured"
OPTIONS=''
FILE_QUALITY='/etc/security/pwquality.conf'
# This function will be called if the script status is on enabled / audit mode
audit() {
for PW_OPT in $OPTIONS; do
PW_PARAM=$(echo "$PW_OPT" | cut -d= -f1)
PW_VALUE=$(echo "$PW_OPT" | cut -d= -f2)
PATTERN="^${PW_PARAM}[[:space:]]?+=[[:space:]]?+$PW_VALUE"
does_pattern_exist_in_file "$FILE_QUALITY" "$PATTERN"
if [ "$FNRET" = 0 ]; then
ok "$PATTERN is present in $FILE_QUALITY"
else
crit "$PATTERN is not present in $FILE_QUALITY"
fi
done
}
# This function will be called if the script status is on enabled mode
apply() {
for PW_OPT in $OPTIONS; do
PW_PARAM=$(echo "$PW_OPT" | cut -d= -f1)
PW_VALUE=$(echo "$PW_OPT" | cut -d= -f2)
# note : dont backslash regex characters, as 'does_pattern_exist_in_file' use "grep -E" which don't need it
PATTERN="^${PW_PARAM}[[:space:]]?+=[[:space:]]?+$PW_VALUE"
does_pattern_exist_in_file "$FILE_QUALITY" "$PATTERN"
if [ "$FNRET" = 0 ]; then
ok "$PATTERN is present in $FILE_QUALITY"
else
warn "$PATTERN is not present in $FILE_QUALITY, adding it"
does_pattern_exist_in_file "$FILE_QUALITY" "^${PW_PARAM}"
if [ "$FNRET" != 0 ]; then
add_end_of_file "$FILE_QUALITY" "$PW_PARAM = $PW_VALUE"
else
info "Parameter $PW_PARAM is present but with the wrong value -- Fixing"
replace_in_file "$FILE_QUALITY" "^${PW_PARAM}*.*" "$PW_PARAM = $PW_VALUE"
fi
fi
done
}
# This function will create the config file for this check with default values
create_config() {
cat <<EOF
status=audit
# Put your custom configuration here
OPTIONS="maxrepeat=3"
EOF
}
# This function will check config parameters required
check_config() {
:
}
# Source Root Dir Parameter
if [ -r /etc/default/cis-hardening ]; then
# shellcheck source=../../debian/default
. /etc/default/cis-hardening
fi
if [ -z "$CIS_LIB_DIR" ]; then
echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment."
echo "Cannot source CIS_LIB_DIR variable, aborting."
exit 128
fi
# Main function, will call the proper functions given the configuration (audit, enabled, disabled)
if [ -r "${CIS_LIB_DIR}"/main.sh ]; then
# shellcheck source=../../lib/main.sh
. "${CIS_LIB_DIR}"/main.sh
else
echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening"
exit 128
fi

View File

@ -0,0 +1,94 @@
#!/bin/bash
# run-shellcheck
#
# CIS Debian Hardening
#
#
# Ensure password maximum sequential characters is configured (Automated)
#
set -e # One error, it's over
set -u # One variable unset, it's over
# shellcheck disable=2034
HARDENING_LEVEL=2
# shellcheck disable=2034
DESCRIPTION="Ensure password maximum sequential characters is configured"
OPTIONS=''
FILE_QUALITY='/etc/security/pwquality.conf'
# This function will be called if the script status is on enabled / audit mode
audit() {
for PW_OPT in $OPTIONS; do
PW_PARAM=$(echo "$PW_OPT" | cut -d= -f1)
PW_VALUE=$(echo "$PW_OPT" | cut -d= -f2)
# note : dont backslash regex characters, as 'does_pattern_exist_in_file' use "grep -E" which don't need it
PATTERN="^${PW_PARAM}[[:space:]]?+=[[:space:]]?+$PW_VALUE"
does_pattern_exist_in_file "$FILE_QUALITY" "$PATTERN"
if [ "$FNRET" = 0 ]; then
ok "$PATTERN is present in $FILE_QUALITY"
else
crit "$PATTERN is not present in $FILE_QUALITY"
fi
done
}
# This function will be called if the script status is on enabled mode
apply() {
for PW_OPT in $OPTIONS; do
PW_PARAM=$(echo "$PW_OPT" | cut -d= -f1)
PW_VALUE=$(echo "$PW_OPT" | cut -d= -f2)
PATTERN="^${PW_PARAM}[[:space:]]?+=[[:space:]]?+$PW_VALUE"
does_pattern_exist_in_file "$FILE_QUALITY" "$PATTERN"
if [ "$FNRET" = 0 ]; then
ok "$PATTERN is present in $FILE_QUALITY"
else
warn "$PATTERN is not present in $FILE_QUALITY, adding it"
does_pattern_exist_in_file "$FILE_QUALITY" "^${PW_PARAM}"
if [ "$FNRET" != 0 ]; then
add_end_of_file "$FILE_QUALITY" "$PW_PARAM = $PW_VALUE"
else
info "Parameter $PW_PARAM is present but with the wrong value -- Fixing"
replace_in_file "$FILE_QUALITY" "^${PW_PARAM}*.*" "$PW_PARAM = $PW_VALUE"
fi
fi
done
}
# This function will create the config file for this check with default values
create_config() {
cat <<EOF
status=audit
# Put your custom configuration here
OPTIONS="maxsequence=3"
EOF
}
# This function will check config parameters required
check_config() {
:
}
# Source Root Dir Parameter
if [ -r /etc/default/cis-hardening ]; then
# shellcheck source=../../debian/default
. /etc/default/cis-hardening
fi
if [ -z "$CIS_LIB_DIR" ]; then
echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment."
echo "Cannot source CIS_LIB_DIR variable, aborting."
exit 128
fi
# Main function, will call the proper functions given the configuration (audit, enabled, disabled)
if [ -r "${CIS_LIB_DIR}"/main.sh ]; then
# shellcheck source=../../lib/main.sh
. "${CIS_LIB_DIR}"/main.sh
else
echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening"
exit 128
fi

View File

@ -0,0 +1,94 @@
#!/bin/bash
# run-shellcheck
#
# CIS Debian Hardening
#
#
# Ensure minimum password length is configured (Automated)
#
set -e # One error, it's over
set -u # One variable unset, it's over
# shellcheck disable=2034
HARDENING_LEVEL=2
# shellcheck disable=2034
DESCRIPTION="Ensure password minimum length is configured "
OPTIONS=''
FILE_QUALITY='/etc/security/pwquality.conf'
# This function will be called if the script status is on enabled / audit mode
audit() {
for PW_OPT in $OPTIONS; do
PW_PARAM=$(echo "$PW_OPT" | cut -d= -f1)
PW_VALUE=$(echo "$PW_OPT" | cut -d= -f2)
# note : dont backslash regex characters, as 'does_pattern_exist_in_file' use "grep -E" which don't need it
PATTERN="^${PW_PARAM}[[:space:]]?+=[[:space:]]?+$PW_VALUE"
does_pattern_exist_in_file "$FILE_QUALITY" "$PATTERN"
if [ "$FNRET" = 0 ]; then
ok "$PATTERN is present in $FILE_QUALITY"
else
crit "$PATTERN is not present in $FILE_QUALITY"
fi
done
}
# This function will be called if the script status is on enabled mode
apply() {
for PW_OPT in $OPTIONS; do
PW_PARAM=$(echo "$PW_OPT" | cut -d= -f1)
PW_VALUE=$(echo "$PW_OPT" | cut -d= -f2)
PATTERN="^${PW_PARAM}[[:space:]]?+=[[:space:]]?+$PW_VALUE"
does_pattern_exist_in_file "$FILE_QUALITY" "$PATTERN"
if [ "$FNRET" = 0 ]; then
ok "$PATTERN is present in $FILE_QUALITY"
else
warn "$PATTERN is not present in $FILE_QUALITY, adding it"
does_pattern_exist_in_file "$FILE_QUALITY" "^${PW_PARAM}"
if [ "$FNRET" != 0 ]; then
add_end_of_file "$FILE_QUALITY" "$PW_PARAM = $PW_VALUE"
else
info "Parameter $PW_PARAM is present but with the wrong value -- Fixing"
replace_in_file "$FILE_QUALITY" "^${PW_PARAM}*.*" "$PW_PARAM = $PW_VALUE"
fi
fi
done
}
# This function will create the config file for this check with default values
create_config() {
cat <<EOF
status=audit
# Put your custom configuration here
OPTIONS="minlen=14"
EOF
}
# This function will check config parameters required
check_config() {
:
}
# Source Root Dir Parameter
if [ -r /etc/default/cis-hardening ]; then
# shellcheck source=../../debian/default
. /etc/default/cis-hardening
fi
if [ -z "$CIS_LIB_DIR" ]; then
echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment."
echo "Cannot source CIS_LIB_DIR variable, aborting."
exit 128
fi
# Main function, will call the proper functions given the configuration (audit, enabled, disabled)
if [ -r "${CIS_LIB_DIR}"/main.sh ]; then
# shellcheck source=../../lib/main.sh
. "${CIS_LIB_DIR}"/main.sh
else
echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening"
exit 128
fi

View File

@ -17,64 +17,48 @@ HARDENING_LEVEL=4
# shellcheck disable=2034
DESCRIPTION="Record events that modify the system's mandatory access controls (MAC)."
AUDIT_PARAMS='-w /etc/selinux/ -p wa -k MAC-policy'
FILES_TO_SEARCH='/etc/audit/audit.rules /etc/audit/rules.d/audit.rules'
FILE='/etc/audit/rules.d/audit.rules'
AUDIT_PARAMS=("-w /etc/apparmor/ -p wa -k MAC-policy" "-w /etc/apparmor.d/ -p wa -k MAC-policy")
AUDIT_FILE='/etc/audit/audit.rules'
ADDITIONAL_PATH="/etc/audit/rules.d"
FILE_TO_WRITE='/etc/audit/rules.d/audit.rules'
# This function will be called if the script status is on enabled / audit mode
audit() {
# define custom IFS and save default one
d_IFS=$IFS
c_IFS=$'\n'
IFS=$c_IFS
for AUDIT_VALUE in $AUDIT_PARAMS; do
debug "$AUDIT_VALUE should be in file $FILES_TO_SEARCH"
IFS=$d_IFS
MISSING_PARAMS=()
index=0
# use find here in order to simplify test usage with sudo using secaudit user
FILES_TO_SEARCH="$(sudo_wrapper find $ADDITIONAL_PATH -name '*.rules' | paste -s) $AUDIT_FILE"
for i in "${!AUDIT_PARAMS[@]}"; do
debug "${AUDIT_PARAMS[i]} should be in file $FILES_TO_SEARCH"
SEARCH_RES=0
for FILE_SEARCHED in $FILES_TO_SEARCH; do
does_pattern_exist_in_file "$FILE_SEARCHED" "$AUDIT_VALUE"
IFS=$c_IFS
does_pattern_exist_in_file "$FILE_SEARCHED" "${AUDIT_PARAMS[i]}"
if [ "$FNRET" != 0 ]; then
debug "$AUDIT_VALUE is not in file $FILE_SEARCHED"
debug "${AUDIT_PARAMS[i]} is not in file $FILE_SEARCHED"
else
ok "$AUDIT_VALUE is present in $FILE_SEARCHED"
ok "${AUDIT_PARAMS[i]} is present in $FILE_SEARCHED"
SEARCH_RES=1
fi
done
if [ "$SEARCH_RES" = 0 ]; then
crit "$AUDIT_VALUE is not present in $FILES_TO_SEARCH"
crit "${AUDIT_PARAMS[i]} is not present in $FILES_TO_SEARCH"
MISSING_PARAMS[i]="${AUDIT_PARAMS[i]}"
index=$((index + 1))
fi
done
IFS=$d_IFS
}
# This function will be called if the script status is on enabled mode
apply() {
# define custom IFS and save default one
d_IFS=$IFS
c_IFS=$'\n'
IFS=$c_IFS
for AUDIT_VALUE in $AUDIT_PARAMS; do
debug "$AUDIT_VALUE should be in file $FILES_TO_SEARCH"
IFS=$d_IFS
SEARCH_RES=0
for FILE_SEARCHED in $FILES_TO_SEARCH; do
does_pattern_exist_in_file "$FILE_SEARCHED" "$AUDIT_VALUE"
IFS=$c_IFS
if [ "$FNRET" != 0 ]; then
debug "$AUDIT_VALUE is not in file $FILE_SEARCHED"
else
ok "$AUDIT_VALUE is present in $FILE_SEARCHED"
SEARCH_RES=1
fi
done
if [ "$SEARCH_RES" = 0 ]; then
warn "$AUDIT_VALUE is not present in $FILES_TO_SEARCH, adding it to $FILE"
add_end_of_file "$FILE" "$AUDIT_VALUE"
eval "$(pkill -HUP -P 1 auditd)"
fi
audit
changes=0
for i in "${!MISSING_PARAMS[@]}"; do
info "${MISSING_PARAMS[i]} is not present in $FILES_TO_SEARCH, adding it"
add_end_of_file "$FILE_TO_WRITE" "${MISSING_PARAMS[i]}"
changes=1
done
IFS=$d_IFS
[ "$changes" -eq 0 ] || eval "$(pkill -HUP -P 1 auditd)"
}
# This function will check config parameters required

View File

@ -73,14 +73,7 @@ apply() {
}
create_config() {
set +u
debug "Debian version : $DEB_MAJ_VER "
if [[ "$DEB_MAJ_VER" -le 7 ]]; then
KEX='diffie-hellman-group-exchange-sha256'
else
KEX='curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256'
fi
set -u
KEX='curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256'
cat <<EOF
status=audit
# Put your KexAlgorithms

View File

@ -30,11 +30,7 @@ audit() {
crit "Cannot get Debian version. Aborting..."
return
fi
if [[ "${DEB_MAJ_VER}" != "sid" ]] && [[ "${DEB_MAJ_VER}" -lt "8" ]]; then
set -u
warn "Debian version too old (${DEB_MAJ_VER}), check does not apply, you should disable this check."
return
fi
set -u
is_pkg_installed "$PACKAGE"
if [ "$FNRET" != 0 ]; then

View File

@ -0,0 +1,161 @@
#!/bin/bash
# run-shellcheck
#
# CIS Debian Hardening
#
#
# Ensure local interactive user home directories are configured (Automated)
#
set -e # One error, it's over
set -u # One variable unset, it's over
# shellcheck disable=2034
HARDENING_LEVEL=2
# shellcheck disable=2034
DESCRIPTION="Users are assigned valid home directories"
# a home is purposefully owned by another user
# format: <dir>:<user_name>:<owner_name>
# ex: HOME_OWNER_EXCEPTIONS="/usr/sbin:daemon:root"
HOME_OWNER_EXCEPTIONS=""
# space separated list of path, where permissions are different than 0750
HOME_PERM_EXCEPTIONS=""
ERRORS=0
check_home_owner() {
# user owns home
local user=$1
local home=$2
FNRET=0
owner=$(stat -L -c "%U" "$home")
if [ "$owner" != "$user" ]; then
EXCEP_FOUND=0
for excep in $HOME_OWNER_EXCEPTIONS; do
if [ "$home:$user:$owner" = "$excep" ]; then
ok "The home directory ($home) of user $user is owned by $owner but is part of exceptions ($home:$user:$owner)."
EXCEP_FOUND=1
break
fi
done
if [ "$EXCEP_FOUND" -eq 0 ]; then
crit "The home directory ($home) of user $user is owned by $owner."
FNRET=1
fi
fi
}
check_home_perm() {
# 750 or more restrictive
local home=$1
HOME_PERM_ERRORS=0
debug "Exceptions : $HOME_PERM_EXCEPTIONS"
debug "echo \"$HOME_PERM_EXCEPTIONS\" | grep -q $home"
if echo "$HOME_PERM_EXCEPTIONS" | grep -q "$home"; then
debug "$home is confirmed as an exception"
# shellcheck disable=SC2001
RESULT=$(sed "s!$home!!" <<<"$RESULT")
else
debug "$home not found in exceptions"
fi
if [ -d "$home" ]; then
dirperm=$(/bin/ls -ld "$home" | cut -f1 -d" ")
if [ "$(echo "$dirperm" | cut -c6)" != "-" ]; then
crit "Group Write permission set on directory $home"
HOME_PERM_ERRORS=$((HOME_PERM_ERRORS + 1))
fi
if [ "$(echo "$dirperm" | cut -c8)" != "-" ]; then
crit "Other Read permission set on directory $home"
HOME_PERM_ERRORS=$((HOME_PERM_ERRORS + 1))
fi
if [ "$(echo "$dirperm" | cut -c9)" != "-" ]; then
crit "Other Write permission set on directory $home"
HOME_PERM_ERRORS=$((HOME_PERM_ERRORS + 1))
fi
if [ "$(echo "$dirperm" | cut -c10)" != "-" ]; then
crit "Other Execute permission set on directory $home"
HOME_PERM_ERRORS=$((HOME_PERM_ERRORS + 1))
fi
fi
}
# This function will be called if the script status is on enabled / audit mode
audit() {
RESULT=$(get_db passwd | awk -F: '{ print $1 ":" $3 ":" $6 }')
for LINE in $RESULT; do
debug "Working on $LINE"
USER=$(awk -F: '{print $1}' <<<"$LINE")
USERID=$(awk -F: '{print $2}' <<<"$LINE")
DIR=$(awk -F: '{print $3}' <<<"$LINE")
if [ "$USERID" -ge 1000 ]; then
if [ ! -d "$DIR" ] && [ "$USER" != "nfsnobody" ] && [ "$USER" != "nobody" ] && [ "$DIR" != "/nonexistent" ]; then
crit "The home directory ($DIR) of user $USER does not exist."
ERRORS=$((ERRORS + 1))
fi
if [ -d "$DIR" ] && [ "$USER" != "nfsnobody" ]; then
check_home_owner "$USER" "$DIR"
[ $FNRET -ne 0 ] && ERRORS=$((ERRORS + 1))
fi
fi
done
for DIR in $(get_db passwd | grep -Ev '(root|halt|sync|shutdown)' | awk -F: '($7 != "/usr/sbin/nologin" && $7 != "/sbin/nologin" && $7 != "/bin/false" && $7 !="/nonexistent" ) { print $6 }'); do
check_home_perm "$DIR"
ERRORS=$((ERRORS + HOME_PERM_ERRORS))
done
if [ "$ERRORS" -eq 0 ]; then
ok "All home directories are correctly configured"
fi
}
# This function will be called if the script status is on enabled mode
apply() {
info "Modifying home directories may seriously harm your system, report only here"
}
create_config() {
cat <<EOF
status=audit
# Put here user home directories exceptions
# format: <dir>:<user_name>:<owner_name>
HOME_OWNER_EXCEPTIONS=""
# space separated list of path, where permissions are different than 0750
HOME_PERM_EXCEPTIONS=""
EOF
}
# This function will check config parameters required
check_config() {
if [ -z "$HOME_PERM_EXCEPTIONS" ]; then
HOME_PERM_EXCEPTIONS="@"
fi
}
# Source Root Dir Parameter
if [ -r /etc/default/cis-hardening ]; then
# shellcheck source=../../debian/default
. /etc/default/cis-hardening
fi
if [ -z "$CIS_LIB_DIR" ]; then
echo "There is no /etc/default/cis-hardening file nor cis-hardening directory in current environment."
echo "Cannot source CIS_LIB_DIR variable, aborting."
exit 128
fi
# Main function, will call the proper functions given the configuration (audit, enabled, disabled)
if [ -r "${CIS_LIB_DIR}"/main.sh ]; then
# shellcheck source=../../lib/main.sh
. "${CIS_LIB_DIR}"/main.sh
else
echo "Cannot find main.sh, have you correctly defined your root directory? Current value is $CIS_LIB_DIR in /etc/default/cis-hardening"
exit 128
fi

9
debian/changelog vendored
View File

@ -1,3 +1,12 @@
cis-hardening (4.1-5) unstable; urgency=medium
* drop debian10 and below support
* fix: ipv6_is_enabled (#251)
* fix: record_mac_edit.sh (#195)
* add --set-version to manage multiple cis versions in the future
-- Damien Cavagnini <damien.cavagnini@ovhcloud.com> Fri, 04 Jul 2025 10:27:18 +0200
cis-hardening (4.1-4) unstable; urgency=medium
* allow multiple users in 5.2.18 (#228)

View File

@ -4,13 +4,13 @@
.hy
.SH NAME
.PP
cis-hardening - CIS Debian 10/11/12 Hardening
cis-hardening - CIS Debian 11/12 Hardening
.SH SYNOPSIS
.PP
\f[B]hardening.sh\f[R] RUN_MODE OPTIONS
.SH DESCRIPTION
.PP
Modular Debian 10/11/12 security hardening scripts based on the CIS
Modular Debian 11/12 security hardening scripts based on the CIS
(https://www.cisecurity.org) recommendations.
.PP
We use it at OVHcloud (https://www.ovhcloud.com) to harden our PCI-DSS

2
debian/control vendored
View File

@ -10,7 +10,7 @@ Vcs-Browser: https://github.com/ovh/debian-cis/
Package: cis-hardening
Architecture: all
Depends: ${misc:Depends}, patch
Depends: ${misc:Depends}, patch, coreutils
Description: Suite of configurable scripts to audit or harden a Debian.
Modular Debian security hardening scripts based on cisecurity.org
⟨cisecurity.org⟩ recommendations. We use it at OVH ⟨https://www.ovh.com⟩ to

View File

@ -57,6 +57,6 @@ get_distribution
get_debian_major_version
# shellcheck disable=SC2034
SMALLEST_SUPPORTED_DEBIAN_VERSION=10
SMALLEST_SUPPORTED_DEBIAN_VERSION=11
# shellcheck disable=SC2034
HIGHEST_SUPPORTED_DEBIAN_VERSION=12

View File

@ -53,7 +53,7 @@ set_sysctl_param() {
#
is_ipv6_enabled() {
SYSCTL_PARAMS='net.ipv6.conf.all.disable_ipv6=1 net.ipv6.conf.default.disable_ipv6=1 net.ipv6.conf.lo.disable_ipv6=1'
local SYSCTL_PARAMS='net.ipv6.conf.all.disable_ipv6=1 net.ipv6.conf.default.disable_ipv6=1 net.ipv6.conf.lo.disable_ipv6=1'
does_sysctl_param_exists "net.ipv6"
local ENABLE=1
@ -64,7 +64,9 @@ is_ipv6_enabled() {
debug "$SYSCTL_PARAM should be set to $SYSCTL_EXP_RESULT"
has_sysctl_param_expected_result "$SYSCTL_PARAM" "$SYSCTL_EXP_RESULT"
if [ "$FNRET" != 0 ]; then
crit "$SYSCTL_PARAM was not set to $SYSCTL_EXP_RESULT"
# we don't want to fail because ipv6 is enabled
# it's just an info that some scripts are going to use to decide what to do
info "$SYSCTL_PARAM was not set to $SYSCTL_EXP_RESULT"
ENABLE=0
fi
done
@ -98,6 +100,15 @@ does_file_exist() {
fi
}
is_file_empty() {
local FILE=$1
if $SUDO_CMD [ -s "$FILE" ]; then
FNRET=1
else
FNRET=0
fi
}
has_file_correct_ownership() {
local FILE=$1
local USER=$2
@ -317,95 +328,109 @@ is_service_enabled() {
#
# Kernel Options checks
#
is_kernel_option_enabled() {
local KERNEL_OPTION="$1"
local MODULE_NAME=""
local MODPROBE_FILTER=""
local RESULT=""
local IS_MONOLITHIC_KERNEL=1
local DEF_MODULE=""
if [ $# -ge 2 ]; then
MODULE_NAME="$2"
fi
if [ $# -ge 3 ]; then
MODPROBE_FILTER="$3"
fi
debug "Detect if lsmod is available and does not return an error code (otherwise consider as a monolithic kernel"
if $SUDO_CMD lsmod >/dev/null 2>&1; then
is_kernel_monolithic() {
debug "Detect if /proc/modules is available, otherwise consider as a monolithic kernel"
if $SUDO_CMD ls /proc/modules >/dev/null 2>&1; then
IS_MONOLITHIC_KERNEL=1
else
IS_MONOLITHIC_KERNEL=0
fi
}
if [ $IS_MONOLITHIC_KERNEL -eq 1 ]; then
if $SUDO_CMD [ -r "/proc/config.gz" ]; then
RESULT=$($SUDO_CMD zgrep "^$KERNEL_OPTION=" /proc/config.gz) || :
elif $SUDO_CMD [ -r "/boot/config-$(uname -r)" ]; then
is_kernel_option_enabled() {
# check if kernel option is configured for the running kernel
local KERNEL_OPTION="$1"
local RESULT=""
is_kernel_monolithic
if [ "$IS_MONOLITHIC_KERNEL" -eq 0 ] && $SUDO_CMD [ -r "/proc/config.gz" ]; then
RESULT=$($SUDO_CMD zgrep "^$KERNEL_OPTION=" /proc/config.gz) || :
fi
# modular kernel, or no configuration found in /proc
if [[ "$RESULT" == "" ]]; then
if $SUDO_CMD [ -r "/boot/config-$(uname -r)" ]; then
RESULT=$($SUDO_CMD grep "^$KERNEL_OPTION=" "/boot/config-$(uname -r)") || :
else
debug "No information about kernel found, you're probably in a container"
info "No information about kernel configuration found"
FNRET=127
return
fi
fi
ANSWER=$(cut -d = -f 2 <<<"$RESULT")
if [ "$ANSWER" = "y" ]; then
debug "Kernel option $KERNEL_OPTION enabled"
FNRET=0
elif [ "$ANSWER" = "n" ]; then
debug "Kernel option $KERNEL_OPTION disabled"
FNRET=1
else
debug "Kernel option $KERNEL_OPTION not found"
FNRET=2 # Not found
fi
if $SUDO_CMD [ "$FNRET" -ne 0 ] && [ -n "$MODULE_NAME" ] && [ -d "/lib/modules/$(uname -r)" ]; then
# also check in modules, because even if not =y, maybe
# the admin compiled it separately later (or out-of-tree)
# as a module (regardless of the fact that we have =m or not)
debug "Checking if we have $MODULE_NAME.ko"
local modulefile
modulefile=$($SUDO_CMD find "/lib/modules/$(uname -r)/" -type f -name "$MODULE_NAME.ko")
if $SUDO_CMD [ -n "$modulefile" ]; then
debug "We do have $modulefile!"
# ... but wait, maybe it's blacklisted? check files in /etc/modprobe.d/ for "blacklist xyz"
if grep -qRE "^\s*blacklist\s+$MODULE_NAME\s*$" /etc/modprobe.d/*.conf; then
debug "... but it's blacklisted!"
FNRET=1 # Not found (found but blacklisted)
fi
# ... but wait, maybe it's override ? check files in /etc/modprobe.d/ for "install xyz /bin/(true|false)"
if grep -aRE "^\s*install\s+$MODULE_NAME\s+/bin/(true|false)\s*$" /etc/modprobe.d/*.conf; then
debug "... but it's override!"
FNRET=1 # Not found (found but override)
fi
FNRET=0 # Found!
fi
fi
local ANSWER=""
ANSWER=$(cut -d = -f 2 <<<"$RESULT")
if [ "$ANSWER" = "y" ]; then
debug "Kernel option $KERNEL_OPTION enabled"
FNRET=0
elif [ "$ANSWER" = "n" ]; then
debug "Kernel option $KERNEL_OPTION disabled"
FNRET=1
else
if [ "$MODPROBE_FILTER" != "" ]; then
DEF_MODULE="$($SUDO_CMD modprobe -n -v "$MODULE_NAME" 2>/dev/null | grep -E "$MODPROBE_FILTER" | tail -1 | xargs)"
else
DEF_MODULE="$($SUDO_CMD modprobe -n -v "$MODULE_NAME" 2>/dev/null | tail -1 | xargs)"
fi
debug "Kernel option $KERNEL_OPTION not found"
FNRET=2 # Not found
fi
}
is_kernel_module_disabled() {
# check if a kernel module is disabled in the modprobe configuration
local MODULE_NAME="$1"
FNRET=1
if [ "$DEF_MODULE" == "install /bin/true" ] || [ "$DEF_MODULE" == "install /bin/false" ]; then
debug "$MODULE_NAME is disabled (blacklist with override)"
FNRET=1
elif [ "$DEF_MODULE" == "" ]; then
debug "$MODULE_NAME is disabled"
FNRET=1
else
debug "$MODULE_NAME is enabled"
local module_is_disabled=0
# is it blacklisted ?
if grep -qE "\s?+[^#]?blacklist\s+$MODULE_NAME\s?$" /etc/modprobe.d/*.conf; then
debug "$MODULE_NAME is blacklisted"
module_is_disabled=1
# maybe it is overriden ? check files in /etc/modprobe.d/ for "install xyz /bin/(true|false)"
elif grep -qE "\s?+[^#]?install\s+$MODULE_NAME\s+/bin/(true|false)\s?$" /etc/modprobe.d/*.conf; then
debug "$MODULE_NAME is disabled"
module_is_disabled=1
fi
if [ "$module_is_disabled" -eq 1 ]; then
debug "$MODULE_NAME is disabled in modprobe config"
FNRET=0
fi
}
is_kernel_module_available() {
# check if a kernel module is loadable, in a non monolithic kernel
local KERNEL_OPTION="$1"
FNRET=1
is_kernel_monolithic
if [ "$IS_MONOLITHIC_KERNEL" -eq 0 ]; then
info "your kernel is monolithic, no need to check for module availability"
return
fi
# look if a module is present as a loadable module in ANY available kernel, per CIS recommendation
# shellcheck disable=2013
for config_file in $($SUDO_CMD grep -l "^$KERNEL_OPTION=" /boot/config-*); do
module_config=$($SUDO_CMD grep "^$KERNEL_OPTION=" "$config_file" | cut -d= -f 2)
if [ "$module_config" == 'm' ]; then
debug "\"${KERNEL_OPTION}=m\" found in $config_file as module"
FNRET=0
fi
done
}
if [ "$($SUDO_CMD lsmod | grep -E "$MODULE_NAME" 2>/dev/null)" != "" ]; then
debug "$MODULE_NAME is enabled"
FNRET=0
fi
is_kernel_module_loaded() {
# check if a kernel module is actually loaded
local KERNEL_OPTION="$1"
local LOADED_MODULE_NAME="$2"
FNRET=1
is_kernel_monolithic
if [ "$IS_MONOLITHIC_KERNEL" -eq 0 ]; then
# check if module is compiled
# if yes, then it is loaded
is_kernel_option_enabled "$KERNEL_OPTION"
elif $SUDO_CMD grep -w "$LOADED_MODULE_NAME" /proc/modules >/dev/null 2>&1; then
debug "$LOADED_MODULE_NAME is loaded in the running kernel in /proc/modules"
FNRET=0 # Found!
fi
}
@ -570,11 +595,7 @@ get_debian_major_version() {
DEB_MAJ_VER=""
does_file_exist /etc/debian_version
if [ "$FNRET" = 0 ]; then
if grep -q "sid" /etc/debian_version; then
DEB_MAJ_VER="sid"
else
DEB_MAJ_VER=$(cut -d '.' -f1 /etc/debian_version)
fi
DEB_MAJ_VER=$(cut -d '.' -f1 /etc/debian_version)
else
# shellcheck disable=2034
DEB_MAJ_VER=$(lsb_release -r | cut -f2 | cut -d '.' -f 1)

View File

@ -1,22 +0,0 @@
FROM debian:buster
LABEL vendor="OVH"
LABEL project="debian-cis"
LABEL url="https://github.com/ovh/debian-cis"
LABEL description="This image is used to run tests"
RUN groupadd -g 500 secaudit && useradd -u 500 -g 500 -s /bin/bash secaudit && install -m 700 -o secaudit -g secaudit -d /home/secaudit
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y openssh-server sudo syslog-ng net-tools auditd
COPY --chown=500:500 . /opt/debian-cis/
COPY debian/default /etc/default/cis-hardening
RUN sed -i 's#cis-hardening#debian-cis#' /etc/default/cis-hardening
COPY cisharden.sudoers /etc/sudoers.d/secaudit
RUN sed -i 's#cisharden#secaudit#' /etc/sudoers.d/secaudit
ENTRYPOINT ["/opt/debian-cis/tests/launch_tests.sh"]

View File

@ -36,35 +36,4 @@ test_audit() {
register_test contain "is present in /etc/login.defs"
run sha512pass "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
# DEB_MAJ_VER cannot be overwritten here;
# therefore we need to trick get_debian_major_version
ORIGINAL_DEB_VER="$(cat /etc/debian_version)"
echo "sid" >/etc/debian_version
describe Running on blank host as sid
register_test retvalshouldbe 0
register_test contain "(SHA512|yescrypt|YESCRYPT)"
# shellcheck disable=2154
run blanksid "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
cp /etc/login.defs /tmp/login.defs.bak
sed -ir 's/ENCRYPT_METHOD[[:space:]]\+.*/ENCRYPT_METHOD MD5/' /etc/login.defs
describe Fail: wrong hash function configuration as sid
register_test retvalshouldbe 1
register_test contain "(SHA512|yescrypt|YESCRYPT)"
run wrongconfsid "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
describe Correcting situation as sid
sed -i 's/audit/enabled/' "${CIS_CONF_DIR}/conf.d/${script}.cfg"
"${CIS_CHECKS_DIR}/${script}.sh" || true
describe Checking resolved state as sid
register_test retvalshouldbe 0
register_test contain "(SHA512|yescrypt|YESCRYPT)"
run sha512passsid "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
# Cleanup
echo -n "$ORIGINAL_DEB_VER" >/etc/debian_version
unset ORIGINAL_DEB_VER
}

View File

@ -21,35 +21,6 @@ test_audit() {
describe Checking resolved state
register_test retvalshouldbe 0
register_test contain "is present in /etc/pam.d/common-password"
run solvedsid "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
# DEB_MAJ_VER cannot be overwritten here;
# therefore we need to trick get_debian_major_version
ORIGINAL_DEB_VER="$(cat /etc/debian_version)"
echo "sid" >/etc/debian_version
describe Running on blank host as sid
register_test retvalshouldbe 0
register_test contain "(sha512|yescrypt)"
run blanksid "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
describe Tests purposely failing as sid
sed -i '/pam_unix.so/ s/sha512/sha256/' "/etc/pam.d/common-password" # Debian 10
sed -i '/pam_unix.so/ s/yescrypt/sha256/' "/etc/pam.d/common-password" # Debian 11+
register_test retvalshouldbe 1
register_test contain "is not present"
run noncompliantsid "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
describe correcting situation as sid
sed -i 's/audit/enabled/' "${CIS_CONF_DIR}/conf.d/${script}.cfg"
"${CIS_CHECKS_DIR}/${script}.sh" --apply || true
describe Checking resolved state as sid
register_test retvalshouldbe 0
register_test contain "is present in /etc/pam.d/common-password"
run solvedsid "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
# Cleanup
echo -n "$ORIGINAL_DEB_VER" >/etc/debian_version
unset ORIGINAL_DEB_VER
}

View File

@ -0,0 +1,40 @@
# shellcheck shell=bash
# run-shellcheck
test_audit() {
local APT_KEY_FILE="/etc/apt/trusted.gpg"
local APT_KEY_PATH="/etc/apt/trusted.gpg.d"
local unsecure_source="/etc/apt/sources.list.d/unsecure.list"
local unsecure_conf_file="/etc/apt/apt.conf.d/unsecure"
# make sure we don't have any key
[ -f "$APT_KEY_FILE" ] && mv "$APT_KEY_FILE" /tmp
[ -d "$APT_KEY_PATH" ] && mv "$APT_KEY_PATH" /tmp
describe Running non compliant missing keys
register_test retvalshouldbe 1
# shellcheck disable=2154
run noncompliant "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
# fix the situation
[ -d /tmp/trusted.gpg.d ] && mv /tmp/trusted.gpg.d /etc/apt/
[ -f /tmp/trusted.gpg ] && mv /tmp/trusted.gpg /etc/apt/
describe Checking resolved state
register_test retvalshouldbe 0
run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
echo 'deb [allow-insecure=yes] http://deb.debian.org/debian bookworm main' >"$unsecure_source"
describe Running non compliant unsecure option in sources list
register_test retvalshouldbe 1
run noncompliant "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
rm -f "$unsecure_source"
echo 'Acquire::AllowInsecureRepositories=true' >"$unsecure_conf_file"
describe Running non compliant unsecure option in apt conf
register_test retvalshouldbe 1
run noncompliant "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
rm -f "$unsecure_conf_file"
}

View File

@ -0,0 +1,16 @@
# shellcheck shell=bash
# run-shellcheck
test_audit() {
describe Running on blank host
register_test retvalshouldbe 0
dismiss_count_for_test
# shellcheck disable=2154
run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
##################################################################
# For this test, we only check that it runs properly on a blank #
# host, and we check root/sudo consistency. But, we don't test #
# the apply function because it can't be automated or it is very #
# long to test and not very useful. #
##################################################################
}

View File

@ -0,0 +1,21 @@
# shellcheck shell=bash
# run-shellcheck
test_audit() {
PATTERN_COMMON='pam_pwquality.so'
FILE_COMMON='/etc/pam.d/common-password'
# create issue
sed -i '/'$PATTERN_COMMON'/d' "$FILE_COMMON"
describe Running non compliant
register_test retvalshouldbe 1
# shellcheck disable=2154
run noncompliant "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
sed -i 's/audit/enabled/' "${CIS_CONF_DIR}/conf.d/${script}.cfg"
"${CIS_CHECKS_DIR}/${script}.sh" || true
describe Checking resolved state
register_test retvalshouldbe 0
run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
}

View File

@ -0,0 +1,16 @@
# shellcheck shell=bash
# run-shellcheck
test_audit() {
describe Running on blank host
register_test retvalshouldbe 0
dismiss_count_for_test
# shellcheck disable=2154
run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
##################################################################
# For this test, we only check that it runs properly on a blank #
# host, and we check root/sudo consistency. But, we don't test #
# the apply function because it can't be automated or it is very #
# long to test and not very useful. #
##################################################################
}

View File

@ -0,0 +1,16 @@
# shellcheck shell=bash
# run-shellcheck
test_audit() {
describe Running on blank host
register_test retvalshouldbe 0
dismiss_count_for_test
# shellcheck disable=2154
run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
##################################################################
# For this test, we only check that it runs properly on a blank #
# host, and we check root/sudo consistency. But, we don't test #
# the apply function because it can't be automated or it is very #
# long to test and not very useful. #
##################################################################
}

View File

@ -0,0 +1,16 @@
# shellcheck shell=bash
# run-shellcheck
test_audit() {
describe Running on blank host
register_test retvalshouldbe 0
dismiss_count_for_test
# shellcheck disable=2154
run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
##################################################################
# For this test, we only check that it runs properly on a blank #
# host, and we check root/sudo consistency. But, we don't test #
# the apply function because it can't be automated or it is very #
# long to test and not very useful. #
##################################################################
}

View File

@ -0,0 +1,28 @@
# shellcheck shell=bash
# run-shellcheck
test_audit() {
local OPTIONS="minclass=3 dcredit=-1 ucredit=-2 ocredit=-1 lcredit=-1"
local FILE_QUALITY='/etc/security/pwquality.conf'
# install dependencies
apt-get update
apt-get install -y libpam-pwquality
# prepare to fail
describe Prepare on purpose failed test
sed -i '/minclass/d' $FILE_QUALITY
describe Running on purpose failed test
register_test retvalshouldbe 1
# shellcheck disable=2154
run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
describe Correcting situation
echo "$OPTIONS" >>"$FILE_QUALITY"
describe Checking resolved state
register_test retvalshouldbe 0
run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
}

View File

@ -0,0 +1,28 @@
# shellcheck shell=bash
# run-shellcheck
test_audit() {
local OPTIONS="maxrepeat=3"
local FILE_QUALITY='/etc/security/pwquality.conf'
# install dependencies
apt-get update
apt-get install -y libpam-pwquality
# prepare to fail
describe Prepare on purpose failed test
sed -i '/maxrepeat/d' $FILE_QUALITY
describe Running on purpose failed test
register_test retvalshouldbe 1
# shellcheck disable=2154
run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
describe Correcting situation
echo "$OPTIONS" >>"$FILE_QUALITY"
describe Checking resolved state
register_test retvalshouldbe 0
run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
}

View File

@ -0,0 +1,28 @@
# shellcheck shell=bash
# run-shellcheck
test_audit() {
local OPTIONS="maxsequence=3"
local FILE_QUALITY='/etc/security/pwquality.conf'
# install dependencies
apt-get update
apt-get install -y libpam-pwquality
# prepare to fail
describe Prepare on purpose failed test
sed -i '/maxsequence/d' $FILE_QUALITY
describe Running on purpose failed test
register_test retvalshouldbe 1
# shellcheck disable=2154
run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
describe Correcting situation
echo "$OPTIONS" >>"$FILE_QUALITY"
describe Checking resolved state
register_test retvalshouldbe 0
run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
}

View File

@ -0,0 +1,27 @@
# shellcheck shell=bash
# run-shellcheck
test_audit() {
local OPTIONS="minlen=14"
local FILE_QUALITY='/etc/security/pwquality.conf'
# install dependencies
apt-get update
apt-get install -y libpam-pwquality
# prepare to fail
describe Prepare on purpose failed test
sed -i '/minlen/d' $FILE_QUALITY
describe Running on purpose failed test
register_test retvalshouldbe 1
# shellcheck disable=2154
run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
describe Correcting situation
echo "$OPTIONS" >>"$FILE_QUALITY"
describe Checking resolved state
register_test retvalshouldbe 0
run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
}

View File

@ -2,8 +2,7 @@
# run-shellcheck
test_audit() {
describe Running on blank host
register_test retvalshouldbe 0
dismiss_count_for_test
register_test retvalshouldbe 1
# shellcheck disable=2154
run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
@ -13,6 +12,6 @@ test_audit() {
describe Checking resolved state
register_test retvalshouldbe 0
register_test contain "[ OK ] -w /etc/selinux/ -p wa -k MAC-policy is present in /etc/audit/rules.d/audit.rules"
register_test contain "[ OK ] -w /etc/apparmor/ -p wa -k MAC-policy is present in /etc/audit/rules.d/audit.rules"
run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
}

View File

@ -0,0 +1,88 @@
# shellcheck shell=bash
# run-shellcheck
test_audit() {
local no_home_test_user="userwithouthome"
local owner_test_user="testhomeuser"
local perm_test_user="testhomepermuser"
describe Running on blank host
register_test retvalshouldbe 0
# shellcheck disable=2154
run blank "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
home_dir_missing "$no_home_test_user"
home_dir_ownership "$owner_test_user"
home_dir_perm "$perm_test_user"
fix_home "$no_home_test_user" "$owner_test_user" "$perm_test_user"
describe Checking resolved state
register_test retvalshouldbe 0
run resolved "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
cleanup "$no_home_test_user" "$owner_test_user" "$perm_test_user"
}
home_dir_missing() {
local test_user="$1"
useradd -d /home/"$test_user" "$test_user"
describe Tests purposely failing that a homdedir does not exists
register_test retvalshouldbe 1
register_test contain "does not exist."
run noncompliant "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
}
home_dir_ownership() {
local test_user="$1"
describe Test purposely failing that a user does not own its home
useradd -d /home/"$test_user" -m "$test_user"
chown root:root /home/"$test_user"
chmod 0750 /home/"$test_user"
register_test retvalshouldbe 1
register_test contain "[ KO ] The home directory (/home/$test_user) of user $test_user is owned by root"
run noncompliant "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
}
home_dir_perm() {
local test_user="$1"
describe Tests purposely failing for wrong permissions on home
useradd -d /home/"$test_user" --create-home "$test_user"
chmod 777 /home/"$test_user"
register_test retvalshouldbe 1
register_test contain "Group Write permission set on directory"
register_test contain "Other Read permission set on directory"
register_test contain "Other Write permission set on directory"
register_test contain "Other Execute permission set on directory"
run noncompliant "${CIS_CHECKS_DIR}/${script}.sh" --audit-all
}
fix_home() {
local missing_home_test_user="$1"
local owner_test_user="$2"
local perm_test_user="$3"
describe correcting situation for missing home
install -d -m 0750 -o "$missing_home_test_user" /home/"$missing_home_test_user"
describe correcting situation for ownership
# we don't want to erase default configurations, or others checks could fail
# shellcheck disable=2086
sed -i '/^HOME_OWNER_EXCEPTIONS/s|HOME_OWNER_EXCEPTIONS=\"|HOME_OWNER_EXCEPTIONS=\"/home/'$owner_test_user':'$owner_test_user':root |' ${CIS_CONF_DIR}/conf.d/${script}.cfg
describe correcting situation for permissions
chmod 0750 /home/"$perm_test_user"
}
cleanup() {
local users="$*"
for user in $users; do
# owner_test_user del will fail as its home is owned by another user
userdel -r "$user" || true
rm -rf /home/"${user:?}" || true
done
}

View File

@ -1 +1 @@
../../bin/hardening/limit_password_reuse.sh
../../bin/hardening/password_history_remember.sh

View File

@ -1 +1 @@
../../bin/hardening/last_password_change_past.sh
../../bin/hardening/password_last_change_past.sh