From 84c762f3512a631642fe24b758e01e1d2220e55d Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 08:53:13 +1200 Subject: [PATCH 01/18] Add CIS Level 1 profiles for Ubuntu 26.04 --- components/apt.yml | 7 +- components/coreutils.yml | 3 + components/cracklib-runtime.yml | 5 + components/pam.yml | 2 + components/update-notifier-common.yml | 6 + .../bash/shared.sh | 14 + .../oval/shared.xml | 17 + .../rule.yml | 12 + .../bash/shared.sh | 14 + .../oval/shared.xml | 17 + .../rule.yml | 11 + .../bash/shared.sh | 14 + .../oval/shared.xml | 17 + .../rule.yml | 12 + .../apt_configure_check_date/bash/shared.sh | 14 + .../apt_configure_check_date/oval/shared.xml | 17 + .../apt/apt_configure_check_date/rule.yml | 12 + .../apt_sources_list_d_https/bash/shared.sh | 13 + .../apt_sources_list_d_https/oval/shared.xml | 35 + .../apt/apt_sources_list_d_https/rule.yml | 30 + .../apt/apt_sources_list_https/bash/shared.sh | 9 + .../apt_sources_list_https/oval/shared.xml | 20 + .../apt/apt_sources_list_https/rule.yml | 20 + .../bash/shared.sh | 13 + .../oval/shared.xml | 41 + .../rule.yml | 15 + .../bash/shared.sh | 13 + .../oval/shared.xml | 44 + .../rule.yml | 22 + .../oval/ubuntu2604.xml | 99 + .../tests/ubuntu2604_default_sources.pass.sh | 18 + .../file_permissions_pam_motd/oval/shared.xml | 39 + .../file_permissions_pam_motd/rule.yml | 21 + .../pam_motd_configured/oval/shared.xml | 51 + .../pam_motd_configured/rule.yml | 25 + .../rule.yml | 17 + .../oval/shared.xml | 39 + .../rule.yml | 22 + .../oval/shared.xml | 39 + .../accounts_user_dot_dirs_ownership/rule.yml | 22 + .../oval/shared.xml | 62 + .../rule.yml | 23 + .../ubuntu2604/controls/cis_ubuntu2604.yml | 2379 +++++++++++++++++ .../profiles/cis_level1_server.profile | 20 + .../profiles/cis_level1_workstation.profile | 20 + 45 files changed, 3364 insertions(+), 1 deletion(-) create mode 100644 components/cracklib-runtime.yml create mode 100644 components/update-notifier-common.yml create mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/bash/shared.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/oval/shared.xml create mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/rule.yml create mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/bash/shared.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/oval/shared.xml create mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/rule.yml create mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/bash/shared.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/oval/shared.xml create mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/rule.yml create mode 100644 linux_os/guide/services/apt/apt_configure_check_date/bash/shared.sh create mode 100644 linux_os/guide/services/apt/apt_configure_check_date/oval/shared.xml create mode 100644 linux_os/guide/services/apt/apt_configure_check_date/rule.yml create mode 100644 linux_os/guide/services/apt/apt_sources_list_d_https/bash/shared.sh create mode 100644 linux_os/guide/services/apt/apt_sources_list_d_https/oval/shared.xml create mode 100644 linux_os/guide/services/apt/apt_sources_list_d_https/rule.yml create mode 100644 linux_os/guide/services/apt/apt_sources_list_https/bash/shared.sh create mode 100644 linux_os/guide/services/apt/apt_sources_list_https/oval/shared.xml create mode 100644 linux_os/guide/services/apt/apt_sources_list_https/rule.yml create mode 100644 linux_os/guide/services/base/service_update-notifier-motd_disabled/bash/shared.sh create mode 100644 linux_os/guide/services/base/service_update-notifier-motd_disabled/oval/shared.xml create mode 100644 linux_os/guide/services/base/service_update-notifier-motd_disabled/rule.yml create mode 100644 linux_os/guide/services/base/timer_update-notifier-motd_disabled/bash/shared.sh create mode 100644 linux_os/guide/services/base/timer_update-notifier-motd_disabled/oval/shared.xml create mode 100644 linux_os/guide/services/base/timer_update-notifier-motd_disabled/rule.yml create mode 100644 linux_os/guide/services/ntp/chronyd_specify_remote_server/oval/ubuntu2604.xml create mode 100644 linux_os/guide/services/ntp/chronyd_specify_remote_server/tests/ubuntu2604_default_sources.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/oval/shared.xml create mode 100644 linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/rule.yml create mode 100644 linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/oval/shared.xml create mode 100644 linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/rule.yml create mode 100644 linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/rule.yml create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/oval/shared.xml create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/rule.yml create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/oval/shared.xml create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/rule.yml create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/oval/shared.xml create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/rule.yml create mode 100644 products/ubuntu2604/controls/cis_ubuntu2604.yml create mode 100644 products/ubuntu2604/profiles/cis_level1_server.profile create mode 100644 products/ubuntu2604/profiles/cis_level1_workstation.profile diff --git a/components/apt.yml b/components/apt.yml index d8afbd8eb65d..f8be65f70e23 100644 --- a/components/apt.yml +++ b/components/apt.yml @@ -7,7 +7,13 @@ rules: - apt_conf_disallow_unauthenticated - apt_conf_disable_recommends - apt_conf_disable_suggests +- apt_configure_allow_downgrade_to_insecure_repositories +- apt_configure_allow_insecure_repositories +- apt_configure_allow_weak_repositories +- apt_configure_check_date - apt_disable_weak_dependencies +- apt_sources_list_d_https +- apt_sources_list_https - apt_sources_list_official - directory_groupowner_apt_auth_conf_d - directory_groupowner_apt_sources_list_d @@ -30,4 +36,3 @@ rules: - file_permissions_apt_auth_conf_d - file_permissions_apt_gpg_keys - file_permissions_apt_sources_list_d - diff --git a/components/coreutils.yml b/components/coreutils.yml index 45709b5c8b33..999fccf8ed42 100644 --- a/components/coreutils.yml +++ b/components/coreutils.yml @@ -2,6 +2,9 @@ name: coreutils packages: - coreutils rules: +- accounts_user_dot_dirs_groupownership +- accounts_user_dot_dirs_ownership +- accounts_user_dot_dirs_permissions - accounts_user_dot_group_ownership - accounts_user_dot_no_world_writable_programs - accounts_user_dot_user_ownership diff --git a/components/cracklib-runtime.yml b/components/cracklib-runtime.yml new file mode 100644 index 000000000000..212841831690 --- /dev/null +++ b/components/cracklib-runtime.yml @@ -0,0 +1,5 @@ +name: cracklib-runtime +packages: +- cracklib-runtime +rules: +- package_cracklib-runtime_installed diff --git a/components/pam.yml b/components/pam.yml index 5db9f0134893..b4ccf2781804 100644 --- a/components/pam.yml +++ b/components/pam.yml @@ -126,6 +126,7 @@ rules: - file_permissions_etc_issue - file_permissions_etc_issue_net - file_permissions_etc_motd +- file_permissions_pam_motd - file_permissions_lastlog - group_unique_id - group_unique_name @@ -157,6 +158,7 @@ rules: - package_pcsc-lite_installed - package_screen_installed - pam_disable_automatic_configuration +- pam_motd_configured - passwd_system-auth_substack - policy_temp_passwords_immediate_change - prevent_direct_root_logins diff --git a/components/update-notifier-common.yml b/components/update-notifier-common.yml new file mode 100644 index 000000000000..e962aff2d504 --- /dev/null +++ b/components/update-notifier-common.yml @@ -0,0 +1,6 @@ +name: update-notifier-common +packages: +- update-notifier-common +rules: +- service_update-notifier-motd_disabled +- timer_update-notifier-motd_disabled diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/bash/shared.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/bash/shared.sh new file mode 100644 index 000000000000..946702967ee4 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/bash/shared.sh @@ -0,0 +1,14 @@ +# platform = multi_platform_ubuntu +# reboot = false +# strategy = restrict +# complexity = low +# disruption = low + +config_file=/etc/apt/apt.conf.d/99-cis-repository-security +setting='Acquire::AllowDowngradeToInsecureRepositories "0";' +touch "$config_file" +sed -ri '/^[[:space:]]*Acquire::AllowDowngradeToInsecureRepositories[[:space:]]+/d' "$config_file" +if [ -s "$config_file" ] && [ -n "$(tail -c 1 "$config_file")" ]; then + printf '\n' >> "$config_file" +fi +printf '%s\n' "$setting" >> "$config_file" diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/oval/shared.xml b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/oval/shared.xml new file mode 100644 index 000000000000..b99a2f91051c --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/oval/shared.xml @@ -0,0 +1,17 @@ + + + {{{ oval_metadata("APT does not allow downgrade to insecure repositories.", rule_title=rule_title) }}} + + + + + + + + + /etc/apt/apt\.conf(\.d/.*)?$ + ^[\s]*(?i)Acquire::AllowDowngradeToInsecureRepositories(?-i)[\s]+"?(?i)(1|true|yes|with|on)(?-i)"?[\s]*;[\s]*(#.*)?$ + 1 + + diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/rule.yml b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/rule.yml new file mode 100644 index 000000000000..e92b7b33eab9 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/rule.yml @@ -0,0 +1,12 @@ +documentation_complete: true + +title: 'Disable APT AllowDowngradeToInsecureRepositories' + +description: |- + Configure APT with + Acquire::AllowDowngradeToInsecureRepositories "0";. + +rationale: |- + A repository that loses authentication must not silently remain usable. + +severity: high diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/bash/shared.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/bash/shared.sh new file mode 100644 index 000000000000..afe85025241a --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/bash/shared.sh @@ -0,0 +1,14 @@ +# platform = multi_platform_ubuntu +# reboot = false +# strategy = restrict +# complexity = low +# disruption = low + +config_file=/etc/apt/apt.conf.d/99-cis-repository-security +setting='Acquire::AllowInsecureRepositories "0";' +touch "$config_file" +sed -ri '/^[[:space:]]*Acquire::AllowInsecureRepositories[[:space:]]+/d' "$config_file" +if [ -s "$config_file" ] && [ -n "$(tail -c 1 "$config_file")" ]; then + printf '\n' >> "$config_file" +fi +printf '%s\n' "$setting" >> "$config_file" diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/oval/shared.xml b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/oval/shared.xml new file mode 100644 index 000000000000..b630b5740450 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/oval/shared.xml @@ -0,0 +1,17 @@ + + + {{{ oval_metadata("APT does not explicitly allow insecure repositories.", rule_title=rule_title) }}} + + + + + + + + + /etc/apt/apt\.conf(\.d/.*)?$ + ^[\s]*(?i)Acquire::AllowInsecureRepositories(?-i)[\s]+"?(?i)(1|true|yes|with|on)(?-i)"?[\s]*;[\s]*(#.*)?$ + 1 + + diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/rule.yml b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/rule.yml new file mode 100644 index 000000000000..60809b0b2ed5 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/rule.yml @@ -0,0 +1,11 @@ +documentation_complete: true + +title: 'Disable APT AllowInsecureRepositories' + +description: |- + Configure APT with Acquire::AllowInsecureRepositories "0";. + +rationale: |- + Insecure repositories do not provide authenticated package metadata. + +severity: high diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/bash/shared.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/bash/shared.sh new file mode 100644 index 000000000000..7a7273cc6d02 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/bash/shared.sh @@ -0,0 +1,14 @@ +# platform = multi_platform_ubuntu +# reboot = false +# strategy = restrict +# complexity = low +# disruption = low + +config_file=/etc/apt/apt.conf.d/99-cis-repository-security +setting='Acquire::AllowWeakRepositories "0";' +touch "$config_file" +sed -ri '/^[[:space:]]*Acquire::AllowWeakRepositories[[:space:]]+/d' "$config_file" +if [ -s "$config_file" ] && [ -n "$(tail -c 1 "$config_file")" ]; then + printf '\n' >> "$config_file" +fi +printf '%s\n' "$setting" >> "$config_file" diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/oval/shared.xml b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/oval/shared.xml new file mode 100644 index 000000000000..fc69dd71cb9a --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/oval/shared.xml @@ -0,0 +1,17 @@ + + + {{{ oval_metadata("APT does not explicitly allow weak repositories.", rule_title=rule_title) }}} + + + + + + + + + /etc/apt/apt\.conf(\.d/.*)?$ + ^[\s]*(?i)Acquire::AllowWeakRepositories(?-i)[\s]+"?(?i)(1|true|yes|with|on)(?-i)"?[\s]*;[\s]*(#.*)?$ + 1 + + diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/rule.yml b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/rule.yml new file mode 100644 index 000000000000..3982f8b3048e --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/rule.yml @@ -0,0 +1,12 @@ +documentation_complete: true + +title: 'Disable APT AllowWeakRepositories' + +description: |- + Configure APT with Acquire::AllowWeakRepositories "0";. + +rationale: |- + Weak repositories use package metadata authentication that does not meet + current cryptographic requirements. + +severity: high diff --git a/linux_os/guide/services/apt/apt_configure_check_date/bash/shared.sh b/linux_os/guide/services/apt/apt_configure_check_date/bash/shared.sh new file mode 100644 index 000000000000..5eca2ee6e67c --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_check_date/bash/shared.sh @@ -0,0 +1,14 @@ +# platform = multi_platform_ubuntu +# reboot = false +# strategy = restrict +# complexity = low +# disruption = low + +config_file=/etc/apt/apt.conf.d/99-cis-repository-security +setting='Acquire::Check-Date "true";' +touch "$config_file" +sed -ri '/^[[:space:]]*Acquire::Check-Date[[:space:]]+/d' "$config_file" +if [ -s "$config_file" ] && [ -n "$(tail -c 1 "$config_file")" ]; then + printf '\n' >> "$config_file" +fi +printf '%s\n' "$setting" >> "$config_file" diff --git a/linux_os/guide/services/apt/apt_configure_check_date/oval/shared.xml b/linux_os/guide/services/apt/apt_configure_check_date/oval/shared.xml new file mode 100644 index 000000000000..b746a2278740 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_check_date/oval/shared.xml @@ -0,0 +1,17 @@ + + + {{{ oval_metadata("APT date checking is not explicitly disabled.", rule_title=rule_title) }}} + + + + + + + + + /etc/apt/apt\.conf(\.d/.*)?$ + ^[\s]*(?i)Acquire::Check-Date(?-i)[\s]+"?(?i)(0|false|no|without|off)(?-i)"?[\s]*;[\s]*(#.*)?$ + 1 + + diff --git a/linux_os/guide/services/apt/apt_configure_check_date/rule.yml b/linux_os/guide/services/apt/apt_configure_check_date/rule.yml new file mode 100644 index 000000000000..ddcaebbee12a --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_check_date/rule.yml @@ -0,0 +1,12 @@ +documentation_complete: true + +title: 'Enable APT Check-Date' + +description: |- + Configure APT with Acquire::Check-Date "true";. + +rationale: |- + APT must validate repository metadata dates to reject stale or not-yet-valid + repository metadata. + +severity: high diff --git a/linux_os/guide/services/apt/apt_sources_list_d_https/bash/shared.sh b/linux_os/guide/services/apt/apt_sources_list_d_https/bash/shared.sh new file mode 100644 index 000000000000..3ff6c5c42b75 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_d_https/bash/shared.sh @@ -0,0 +1,13 @@ +# platform = multi_platform_ubuntu +# reboot = false +# strategy = restrict +# complexity = low +# disruption = high + +while IFS= read -r -d '' file; do + sed -ri '/^[[:space:]]*deb(-src)?[[:space:]]+(\[[^]]*\][[:space:]]+)?http:\/\// s#http://#https://#' "$file" +done < <(find /etc/apt/sources.list.d -maxdepth 1 -type f -name '*.list' -print0 2>/dev/null) + +while IFS= read -r -d '' file; do + sed -ri '/^[[:space:]]*URIs:[[:space:]]/I s#http://#https://#g' "$file" +done < <(find /etc/apt/sources.list.d -maxdepth 1 -type f -name '*.sources' -print0 2>/dev/null) diff --git a/linux_os/guide/services/apt/apt_sources_list_d_https/oval/shared.xml b/linux_os/guide/services/apt/apt_sources_list_d_https/oval/shared.xml new file mode 100644 index 000000000000..ac8e2877df18 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_d_https/oval/shared.xml @@ -0,0 +1,35 @@ + + + {{{ oval_metadata("APT repositories in /etc/apt/sources.list.d use HTTPS.", rule_title=rule_title) }}} + + + + + + + + + + + /etc/apt/sources.list.d + .*\.list$ + ^[\s]*deb(-src)?[\s]+(\[[^\]]*\][\s]+)?http://.*$ + 1 + + + + + + + /etc/apt/sources.list.d + .*\.sources$ + ^[\s]*(?i)URIs(?-i):[\s]+[^#\n]*http://.*$ + 1 + + diff --git a/linux_os/guide/services/apt/apt_sources_list_d_https/rule.yml b/linux_os/guide/services/apt/apt_sources_list_d_https/rule.yml new file mode 100644 index 000000000000..2bed5e6564c0 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_d_https/rule.yml @@ -0,0 +1,30 @@ +documentation_complete: true + +title: 'Use HTTPS for Repositories in /etc/apt/sources.list.d' + +description: |- + Active legacy and deb822 APT repository entries below + /etc/apt/sources.list.d must use HTTPS rather than HTTP. + +rationale: |- + HTTPS protects repository metadata and package downloads from network + observation and modification in transit. + +severity: high + +warnings: + - general: |- + Ubuntu ships /etc/apt/sources.list.d/ubuntu.sources using + http://archive.ubuntu.com and http://security.ubuntu.com, + so this rule fails on a default installation. The remediation rewrites + every active http:// entry to https://, including entries + for third-party repositories. A repository that does not serve HTTPS will + become unreachable and apt operations will fail until the entry is + corrected by hand. Review the repositories in use before remediating. + +ocil_clause: 'an active repository entry uses HTTP' + +ocil: |- + Search *.list files for active deb http:// entries and + *.sources files for active URIs: http:// entries. Neither + search may produce output. diff --git a/linux_os/guide/services/apt/apt_sources_list_https/bash/shared.sh b/linux_os/guide/services/apt/apt_sources_list_https/bash/shared.sh new file mode 100644 index 000000000000..a508d9c70a68 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_https/bash/shared.sh @@ -0,0 +1,9 @@ +# platform = multi_platform_ubuntu +# reboot = false +# strategy = restrict +# complexity = low +# disruption = medium + +if [[ -f /etc/apt/sources.list ]]; then + sed -ri '/^[[:space:]]*deb(-src)?[[:space:]]+(\[[^]]*\][[:space:]]+)?http:\/\// s#http://#https://#' /etc/apt/sources.list +fi diff --git a/linux_os/guide/services/apt/apt_sources_list_https/oval/shared.xml b/linux_os/guide/services/apt/apt_sources_list_https/oval/shared.xml new file mode 100644 index 000000000000..4d41e9ec9ef5 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_https/oval/shared.xml @@ -0,0 +1,20 @@ + + + {{{ oval_metadata("APT repositories in /etc/apt/sources.list use HTTPS.", rule_title=rule_title) }}} + + + + + + + + + + /etc/apt/sources.list + ^[\s]*deb(-src)?[\s]+(\[[^\]]*\][\s]+)?http://.*$ + 1 + + diff --git a/linux_os/guide/services/apt/apt_sources_list_https/rule.yml b/linux_os/guide/services/apt/apt_sources_list_https/rule.yml new file mode 100644 index 000000000000..0edc45d10062 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_https/rule.yml @@ -0,0 +1,20 @@ +documentation_complete: true + +title: 'Use HTTPS for Repositories in /etc/apt/sources.list' + +description: |- + Active APT repository entries in /etc/apt/sources.list, including + deb-src entries and entries carrying an options block such as + [signed-by=...], must use HTTPS rather than HTTP. + +rationale: |- + HTTPS protects repository metadata and package downloads from network + observation and modification in transit. + +severity: high + +ocil_clause: 'an active repository entry uses HTTP' + +ocil: |- + Run grep -Pi '^\h*deb(-src)?\h+(\[[^\]]*\]\h+)?http://' /etc/apt/sources.list. + The command must not produce output. diff --git a/linux_os/guide/services/base/service_update-notifier-motd_disabled/bash/shared.sh b/linux_os/guide/services/base/service_update-notifier-motd_disabled/bash/shared.sh new file mode 100644 index 000000000000..0c95f1a1c4d4 --- /dev/null +++ b/linux_os/guide/services/base/service_update-notifier-motd_disabled/bash/shared.sh @@ -0,0 +1,13 @@ +# platform = multi_platform_ubuntu +# reboot = false +# strategy = disable +# complexity = low +# disruption = low + +SYSTEMCTL_EXEC=/usr/bin/systemctl +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop update-notifier-motd.service +fi +"$SYSTEMCTL_EXEC" disable update-notifier-motd.service +"$SYSTEMCTL_EXEC" mask update-notifier-motd.service +"$SYSTEMCTL_EXEC" reset-failed update-notifier-motd.service || true diff --git a/linux_os/guide/services/base/service_update-notifier-motd_disabled/oval/shared.xml b/linux_os/guide/services/base/service_update-notifier-motd_disabled/oval/shared.xml new file mode 100644 index 000000000000..a1673df39456 --- /dev/null +++ b/linux_os/guide/services/base/service_update-notifier-motd_disabled/oval/shared.xml @@ -0,0 +1,41 @@ + + + {{{ oval_metadata("The update-notifier MOTD service is neither enabled nor active.", rule_title=rule_title) }}} + + + + + + + + + + + + + + + + + + + + + update-notifier-motd.service + ActiveState + + + update-notifier-motd.service + UnitFileState + + + active + + + ^(?!enabled).*$ + + diff --git a/linux_os/guide/services/base/service_update-notifier-motd_disabled/rule.yml b/linux_os/guide/services/base/service_update-notifier-motd_disabled/rule.yml new file mode 100644 index 000000000000..3bdd78bdb8c7 --- /dev/null +++ b/linux_os/guide/services/base/service_update-notifier-motd_disabled/rule.yml @@ -0,0 +1,15 @@ +documentation_complete: true + +title: 'Disable and Mask update-notifier-motd Service' + +description: |- + The update-notifier-motd service generates dynamic message-of-the-day + content. {{{ describe_service_disable(service="update-notifier-motd") }}} + +rationale: |- + Disabling dynamic MOTD updates prevents unaudited network and system data + from being added to login banners. + +severity: medium + +platform: system_with_kernel diff --git a/linux_os/guide/services/base/timer_update-notifier-motd_disabled/bash/shared.sh b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/bash/shared.sh new file mode 100644 index 000000000000..c3d3bf6a1a38 --- /dev/null +++ b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/bash/shared.sh @@ -0,0 +1,13 @@ +# platform = multi_platform_ubuntu +# reboot = false +# strategy = disable +# complexity = low +# disruption = low + +SYSTEMCTL_EXEC=/usr/bin/systemctl +if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop update-notifier-motd.timer +fi +"$SYSTEMCTL_EXEC" disable update-notifier-motd.timer +"$SYSTEMCTL_EXEC" mask update-notifier-motd.timer +"$SYSTEMCTL_EXEC" reset-failed update-notifier-motd.timer || true diff --git a/linux_os/guide/services/base/timer_update-notifier-motd_disabled/oval/shared.xml b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/oval/shared.xml new file mode 100644 index 000000000000..b339dc41e97c --- /dev/null +++ b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/oval/shared.xml @@ -0,0 +1,44 @@ + + + {{{ oval_metadata("The update-notifier MOTD timer is disabled and masked.", rule_title=rule_title) }}} + + + + + + + + + + + + + + + + + + + + + + + update-notifier-motd.timer + ActiveState + + + update-notifier-motd.timer + UnitFileState + + + + active + + + ^(?!enabled).*$ + + diff --git a/linux_os/guide/services/base/timer_update-notifier-motd_disabled/rule.yml b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/rule.yml new file mode 100644 index 000000000000..245ee1bbf5b4 --- /dev/null +++ b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/rule.yml @@ -0,0 +1,22 @@ +documentation_complete: true + +title: 'Disable and Mask update-notifier-motd Timer' + +description: |- + The update-notifier-motd.timer unit must be stopped, disabled, and masked + when the update-notifier-common package is installed. + +rationale: |- + Disabling the timer prevents periodic regeneration of dynamic login + message content. + +severity: medium + +platform: system_with_kernel + +ocil_clause: 'update-notifier-motd.timer is active or is not masked' + +ocil: |- + Run systemctl is-active update-notifier-motd.timer and + systemctl is-enabled update-notifier-motd.timer. The timer must be + inactive and masked, or the update-notifier-common package must be absent. diff --git a/linux_os/guide/services/ntp/chronyd_specify_remote_server/oval/ubuntu2604.xml b/linux_os/guide/services/ntp/chronyd_specify_remote_server/oval/ubuntu2604.xml new file mode 100644 index 000000000000..209a5e4369a8 --- /dev/null +++ b/linux_os/guide/services/ntp/chronyd_specify_remote_server/oval/ubuntu2604.xml @@ -0,0 +1,99 @@ + + + {{{ oval_metadata("A remote NTP Server for time synchronization should be + specified (and dependencies are met)", rule_title=rule_title) }}} + + + + + + + + + + + + + {{{ chrony_conf_path }}} + ^[\s]*(?:server|pool)[\s]+.+$ + 1 + + + + {{{ chrony_conf_path }}} + ^[\s]*sourcedir[\s]+(\S+)[\s]*(?:#.*)?$ + 1 + + + + + + /*.sources + + + + + + + + + + + + + + + + ^[\s]*(?:server|pool)[\s]+.+$ + 1 + + + + {{{ chrony_conf_path }}} + ^[\s]*confdir[\s]+(\S+)[\s]*(?:#.*)?$ + 1 + + + + + + /*.conf + + + + + + + + + + + + + + + + ^[\s]*(?:server|pool)[\s]+.+$ + 1 + + diff --git a/linux_os/guide/services/ntp/chronyd_specify_remote_server/tests/ubuntu2604_default_sources.pass.sh b/linux_os/guide/services/ntp/chronyd_specify_remote_server/tests/ubuntu2604_default_sources.pass.sh new file mode 100644 index 000000000000..6f3b68533e1c --- /dev/null +++ b/linux_os/guide/services/ntp/chronyd_specify_remote_server/tests/ubuntu2604_default_sources.pass.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# packages = chrony +# platform = Ubuntu 26.04 + +SOURCES_DIR="/etc/chrony/sources.d" + +rm -rf /etc/chrony/conf.d +rm -rf "$SOURCES_DIR" + +cat > {{{ chrony_conf_path }}} << EOF +sourcedir $SOURCES_DIR +EOF + +mkdir -p "$SOURCES_DIR" +cat > "$SOURCES_DIR/ubuntu-ntp-pools.sources" << EOF +pool 1.ntp.ubuntu.com iburst maxsources 1 nts prefer +pool 2.ntp.ubuntu.com iburst maxsources 1 nts prefer +EOF diff --git a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/oval/shared.xml b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/oval/shared.xml new file mode 100644 index 000000000000..0dc3277cf3f6 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/oval/shared.xml @@ -0,0 +1,39 @@ + + + {{{ oval_metadata("pam_motd message files have secure ownership and permissions.", rule_title=rule_title) }}} + + + + + + + /etc/pam.d + ^(sshd|login|su|gdm-password)$ + ^[\s]*session[\s]+[^#\n]*pam_motd\.so[^#\n]*[\s]motd=([^\s#]+).*$ + 1 + + + + + + + + + + + + + + 0 + 0 + false + false + false + false + false + + diff --git a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/rule.yml b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/rule.yml new file mode 100644 index 000000000000..b3f8030d4cbd --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/rule.yml @@ -0,0 +1,21 @@ +documentation_complete: true + +title: 'Configure Access to pam_motd Message Files' + +description: |- + Files selected by active pam_motd.so motd=PATH arguments must be + owned by root, group-owned by root, and mode 0644 or more restrictive. + +rationale: |- + Restrictive ownership and permissions prevent unauthorized modification of + text displayed to users at login. + +severity: medium + +platform: package[pam] + +ocil_clause: 'a referenced pam_motd file is not root-owned or is more permissive than 0644' + +ocil: |- + Identify paths in active pam_motd.so motd=PATH PAM entries and + verify each path is owned by root:root with mode 0644 or more restrictive. diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/oval/shared.xml b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/oval/shared.xml new file mode 100644 index 000000000000..26f2bab4585b --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/oval/shared.xml @@ -0,0 +1,51 @@ + + + {{{ oval_metadata("pam_motd uses explicit, non-disclosing message files.", rule_title=rule_title) }}} + + + + + + + + + + + + + /etc/pam.d + ^(sshd|login|su|gdm-password)$ + ^[\s]*session[\s]+[^#\n]*pam_motd\.so[^#\n]*[\s]motd=([^\s#]+).*$ + 1 + + + + + + + + + + + + + + + + + + + ^.*(\\[vrms]|(?i:Ubuntu|Debian|GNU/Linux)).*$ + 1 + + diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/rule.yml b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/rule.yml new file mode 100644 index 000000000000..8c09c561e8c6 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/rule.yml @@ -0,0 +1,25 @@ +documentation_complete: true + +title: 'Configure Explicit pam_motd Message Files' + +description: |- + PAM login services using pam_motd.so must specify message files + with an explicit motd= argument. Referenced message files must not + disclose the operating-system release or contain system-information escape + sequences. + +rationale: |- + Explicit message paths make login banner content auditable and prevent + unintended system information disclosure. + +severity: medium + +platform: package[pam] + +ocil_clause: 'pam_motd has no explicit message file or a referenced file discloses system information' + +ocil: |- + Review active pam_motd.so entries in the sshd, login, su, and + gdm-password PAM services. At least one entry must use motd=PATH, + and referenced files must not contain \v, \r, + \m, \s, or distribution-identifying text. diff --git a/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/rule.yml b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/rule.yml new file mode 100644 index 000000000000..97bf501a4096 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/rule.yml @@ -0,0 +1,17 @@ +documentation_complete: true + +title: 'Install cracklib-runtime Package' + +description: |- + {{{ describe_package_install(package="cracklib-runtime") }}} + +rationale: |- + The cracklib-runtime package supplies the password dictionary tools used by + PAM password-quality controls. + +severity: medium + +template: + name: package_installed + vars: + pkgname: cracklib-runtime diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/oval/shared.xml b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/oval/shared.xml new file mode 100644 index 000000000000..53de4d047481 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/oval/shared.xml @@ -0,0 +1,39 @@ + + + {{{ oval_metadata("Interactive user dot directories have valid group owners.", rule_title=rule_title) }}} + + + + + {{%- set home_dirs_object = "object_" ~ rule_id ~ "_home_dirs" -%}} + {{{ create_local_interactive_users_home_dirs_list_object(home_dirs_object) }}} + {{%- set gids_object = "object_" ~ rule_id ~ "_gids" -%}} + {{{ create_local_interactive_users_gids_list_object(gids_object) }}} + + + + + + + + + + + + + + ^\..* + state_{{{ rule_id }}}_directory + + + directory + + + + + diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/rule.yml b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/rule.yml new file mode 100644 index 000000000000..07114647d452 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/rule.yml @@ -0,0 +1,22 @@ +documentation_complete: true + +title: 'Configure Local Interactive User Dot Directory Group Ownership' + +description: |- + Dot directories below local interactive user home directories must be + group-owned by a local interactive user's primary group. + +rationale: |- + Unexpected group ownership can expose private user configuration and + authentication data. + +severity: medium + +platform: system_with_kernel + +ocil_clause: 'a dot directory has an unexpected group owner' + +warnings: + - general: |- + Due to an OVAL limitation, swapped group ownership between two + interactive users can produce a false negative. diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/oval/shared.xml b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/oval/shared.xml new file mode 100644 index 000000000000..48d40094b941 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/oval/shared.xml @@ -0,0 +1,39 @@ + + + {{{ oval_metadata("Interactive user dot directories have valid owners.", rule_title=rule_title) }}} + + + + + {{%- set home_dirs_object = "object_" ~ rule_id ~ "_home_dirs" -%}} + {{{ create_local_interactive_users_home_dirs_list_object(home_dirs_object) }}} + {{%- set uids_object = "object_" ~ rule_id ~ "_uids" -%}} + {{{ create_local_interactive_users_uids_list_object(uids_object) }}} + + + + + + + + + + + + + + ^\..* + state_{{{ rule_id }}}_directory + + + directory + + + + + diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/rule.yml b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/rule.yml new file mode 100644 index 000000000000..142d25521715 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/rule.yml @@ -0,0 +1,22 @@ +documentation_complete: true + +title: 'Configure Local Interactive User Dot Directory Ownership' + +description: |- + Dot directories below local interactive user home directories must be owned + by a local interactive user. + +rationale: |- + Unexpected ownership can allow one account to control another account's + configuration or authentication data. + +severity: medium + +platform: system_with_kernel + +ocil_clause: 'a dot directory has an unexpected owner' + +warnings: + - general: |- + Due to an OVAL limitation, swapped ownership between two interactive + users can produce a false negative. diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/oval/shared.xml b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/oval/shared.xml new file mode 100644 index 000000000000..8bc1931099bd --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/oval/shared.xml @@ -0,0 +1,62 @@ + + + {{{ oval_metadata("Interactive user dot directories have restrictive permissions.", rule_title=rule_title) }}} + + + + + + + {{%- set home_dirs_object = "object_" ~ rule_id ~ "_home_dirs" -%}} + {{{ create_local_interactive_users_home_dirs_list_object(home_dirs_object) }}} + + + + + + + + + + + + ^\..* + state_{{{ rule_id }}}_directory + + + + + + + + + + .ssh + state_{{{ rule_id }}}_directory + + + + directory + + + false + false + false + false + + + false + false + false + false + false + false + + diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/rule.yml b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/rule.yml new file mode 100644 index 000000000000..47c406d0a657 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/rule.yml @@ -0,0 +1,23 @@ +documentation_complete: true + +title: 'Configure Local Interactive User Dot Directory Permissions' + +description: |- + Dot directories below local interactive user home directories must be mode + 0750 or more restrictive. The .ssh directory must be mode 0700 or + more restrictive. + +rationale: |- + Restrictive dot-directory permissions protect private user configuration + and authentication material. + +severity: medium + +platform: system_with_kernel + +ocil_clause: 'a dot directory is too permissive' + +ocil: |- + Find dot directories below every local interactive user home. No directory + may grant group write or any access to other users, and .ssh may not + grant any group access. diff --git a/products/ubuntu2604/controls/cis_ubuntu2604.yml b/products/ubuntu2604/controls/cis_ubuntu2604.yml new file mode 100644 index 000000000000..e9dda51704a2 --- /dev/null +++ b/products/ubuntu2604/controls/cis_ubuntu2604.yml @@ -0,0 +1,2379 @@ +--- +policy: CIS Benchmark for Ubuntu 26.04 LTS +title: CIS Benchmark for Ubuntu 26.04 LTS +id: cis_ubuntu2604 +version: "1.0.0" +source: https://www.cisecurity.org/cis-benchmarks + +levels: + - id: l1_server + - id: l2_server + inherits_from: + - l1_server + - id: l1_workstation + - id: l2_workstation + inherits_from: + - l1_workstation +reference_type: cis +product: ubuntu2604 + +controls: + - id: 1.1.1.1 + title: Ensure cramfs kernel module is not available (Automated) + levels: + - l1_server + - l1_workstation + rules: + - kernel_module_cramfs_disabled + status: automated + - id: 1.1.1.2 + title: Ensure freevxfs kernel module is not available (Automated) + levels: + - l1_server + - l1_workstation + rules: + - kernel_module_freevxfs_disabled + status: automated + - id: 1.1.1.3 + title: Ensure hfs kernel module is not available (Automated) + levels: + - l1_server + - l1_workstation + rules: + - kernel_module_hfs_disabled + status: automated + - id: 1.1.1.4 + title: Ensure hfsplus kernel module is not available (Automated) + levels: + - l1_server + - l1_workstation + rules: + - kernel_module_hfsplus_disabled + status: automated + - id: 1.1.1.5 + title: Ensure jffs2 kernel module is not available (Automated) + levels: + - l1_server + - l1_workstation + rules: + - kernel_module_jffs2_disabled + status: automated + - id: 1.1.1.9 + title: Ensure firewire-core kernel module is not available (Automated) + levels: + - l1_server + - l2_workstation + rules: + - kernel_module_firewire-core_disabled + status: automated + - id: 1.1.1.10 + title: Ensure usb-storage kernel module is not available (Automated) + levels: + - l1_server + - l2_workstation + rules: + - kernel_module_usb-storage_disabled + status: automated + - id: 1.1.1.11 + title: Ensure unused filesystems kernel modules are not available (Manual) + levels: + - l1_server + - l1_workstation + status: manual + - id: 1.1.2.1.1 + title: Ensure /tmp is tmpfs or a separate partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - partition_for_tmp + status: automated + - id: 1.1.2.1.2 + title: Ensure nodev option set on /tmp partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_tmp_nodev + status: automated + - id: 1.1.2.1.3 + title: Ensure nosuid option set on /tmp partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_tmp_nosuid + status: automated + - id: 1.1.2.1.4 + title: Ensure noexec option set on /tmp partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_tmp_noexec + status: automated + - id: 1.1.2.2.1 + title: Ensure /dev/shm is tmpfs or a separate partition (Automated) + levels: + - l1_server + - l1_workstation + status: automated + rules: + - partition_for_dev_shm + - id: 1.1.2.2.2 + title: Ensure nodev option set on /dev/shm partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_dev_shm_nodev + status: automated + - id: 1.1.2.2.3 + title: Ensure nosuid option set on /dev/shm partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_dev_shm_nosuid + status: automated + - id: 1.1.2.2.4 + title: Ensure noexec option set on /dev/shm partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_dev_shm_noexec + status: automated + - id: 1.1.2.3.2 + title: Ensure nodev option set on /home partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_home_nodev + status: automated + - id: 1.1.2.3.3 + title: Ensure nosuid option set on /home partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_home_nosuid + status: automated + - id: 1.1.2.4.2 + title: Ensure nodev option set on /var partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_var_nodev + status: automated + - id: 1.1.2.4.3 + title: Ensure nosuid option set on /var partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_var_nosuid + status: automated + - id: 1.1.2.5.2 + title: Ensure nodev option set on /var/tmp partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_var_tmp_nodev + status: automated + - id: 1.1.2.5.3 + title: Ensure nosuid option set on /var/tmp partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_var_tmp_nosuid + status: automated + - id: 1.1.2.5.4 + title: Ensure noexec option set on /var/tmp partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_var_tmp_noexec + status: automated + - id: 1.1.2.6.2 + title: Ensure nodev option set on /var/log partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_var_log_nodev + status: automated + - id: 1.1.2.6.3 + title: Ensure nosuid option set on /var/log partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_var_log_nosuid + status: automated + - id: 1.1.2.6.4 + title: Ensure noexec option set on /var/log partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_var_log_noexec + status: automated + - id: 1.1.2.7.2 + title: Ensure nodev option set on /var/log/audit partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_var_log_audit_nodev + status: automated + - id: 1.1.2.7.3 + title: Ensure nosuid option set on /var/log/audit partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_var_log_audit_nosuid + status: automated + - id: 1.1.2.7.4 + title: Ensure noexec option set on /var/log/audit partition (Automated) + levels: + - l1_server + - l1_workstation + rules: + - mount_option_var_log_audit_noexec + status: automated + - id: 1.2.1.1 + title: Ensure source.list and .source files use the Signed-By option (Manual) + levels: + - l1_server + - l1_workstation + status: manual + - id: 1.2.1.3 + title: Ensure access to gpg key files are configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_apt_gpg_keys + - file_groupowner_apt_sources_list_d + - file_owner_apt_gpg_keys + - file_owner_apt_sources_list_d + - file_permissions_apt_gpg_keys + - file_permissions_apt_sources_list_d + status: automated + - id: 1.2.1.4 + title: Ensure access to /etc/apt/trusted.gpg.d directory is configured (Automated) + levels: &l1_both + - l1_server + - l1_workstation + rules: + - directory_groupowner_apt_trusted_gpg_d + - directory_owner_apt_trusted_gpg_d + - directory_permissions_apt_trusted_gpg_d + status: automated + - id: 1.2.1.5 + title: Ensure access to /etc/apt/auth.conf.d directory is configured (Automated) + levels: *l1_both + rules: + - directory_groupowner_apt_auth_conf_d + - directory_owner_apt_auth_conf_d + - directory_permissions_apt_auth_conf_d + status: automated + - id: 1.2.1.6 + title: Ensure access to files in /etc/apt/auth.conf.d is configured (Automated) + levels: *l1_both + rules: + - file_groupowner_apt_auth_conf_d + - file_owner_apt_auth_conf_d + - file_permissions_apt_auth_conf_d + status: automated + - id: 1.2.1.7 + title: Ensure access to /usr/share/keyrings directory is configured (Automated) + levels: *l1_both + rules: + - directory_groupowner_usr_share_keyrings + - directory_owner_usr_share_keyrings + - directory_permissions_usr_share_keyrings + status: automated + - id: 1.2.1.8 + title: Ensure access to /etc/apt/sources.list.d directory is configured (Automated) + levels: *l1_both + rules: + - directory_groupowner_apt_sources_list_d + - directory_owner_apt_sources_list_d + - directory_permissions_apt_sources_list_d + status: automated + - id: 1.2.1.9 + title: Ensure access to files in /etc/apt/sources.list.d is configured (Automated) + levels: *l1_both + rules: + - file_groupowner_apt_sources_list_d + - file_owner_apt_sources_list_d + - file_permissions_apt_sources_list_d + status: automated + - id: 1.2.1.10 + title: Ensure repositories are configured to use HTTPS in /etc/apt/sources.list (Automated) + levels: *l1_both + rules: + - apt_sources_list_https + status: automated + - id: 1.2.1.11 + title: Ensure repositories are configured to use HTTPS in /etc/apt/sources.list.d (Automated) + levels: *l1_both + rules: + - apt_sources_list_d_https + status: automated + - id: 1.2.1.12 + title: Ensure AllowInsecureRepositories is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - apt_configure_allow_insecure_repositories + status: automated + - id: 1.2.1.13 + title: Ensure AllowWeakRepositories is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - apt_configure_allow_weak_repositories + status: automated + - id: 1.2.1.14 + title: Ensure AllowDowngradeToInsecureRepositories is configured (Automated) + levels: *l1_both + rules: + - apt_configure_allow_downgrade_to_insecure_repositories + status: automated + - id: 1.2.1.15 + title: Ensure Acquire::Check-Date is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - apt_configure_check_date + status: automated + - id: 1.2.2.1 + title: Ensure updates, patches, and additional security software are installed (Manual) + levels: *l1_both + status: manual + - id: 1.3.1.1 + title: Ensure apparmor packages are installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_apparmor_installed + - package_apparmor-utils_installed + status: automated + - id: 1.3.1.2 + title: Ensure AppArmor is enabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - grub2_enable_apparmor + status: automated + - id: 1.3.1.4 + title: Ensure kernel.apparmor_restrict_unprivileged_unconfined is configured (Automated) + levels: *l1_both + rules: + - sysctl_kernel_apparmor_restrict_unprivileged_unconfined + status: automated + - id: 1.4.1 + title: Ensure bootloader password is set (Automated) + levels: + - l1_server + - l1_workstation + rules: + - grub2_password + status: automated + - id: 1.4.2 + title: Ensure access to bootloader config is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_owner_grub2_cfg + - file_permissions_grub2_cfg + status: automated + - id: 1.5.1 + title: Ensure fs.protected_hardlinks is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_fs_protected_hardlinks + status: automated + - id: 1.5.3 + title: Ensure kernel.yama.ptrace_scope is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_kernel_yama_ptrace_scope_value=1 + - sysctl_kernel_yama_ptrace_scope + status: automated + - id: 1.5.4 + title: Ensure fs.suid_dumpable is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_fs_suid_dumpable + status: automated + - id: 1.5.5 + title: Ensure kernel.dmesg_restrict is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_kernel_dmesg_restrict + status: automated + - id: 1.5.6 + title: Ensure prelink is not installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_prelink_removed + status: automated + - id: 1.5.7 + title: Ensure Automatic Error Reporting is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - service_apport_disabled + status: automated + - id: 1.5.8 + title: Ensure kernel.kptr_restrict is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_kernel_kptr_restrict + status: automated + - id: 1.5.9 + title: Ensure kernel.randomize_va_space is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_kernel_randomize_va_space + status: automated + - id: 1.5.10 + title: Ensure core file size is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - disable_users_coredumps + status: automated + - id: 1.5.11 + title: Ensure systemd-coredump ProcessSizeMax is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - coredump_disable_backtraces + status: automated + - id: 1.5.12 + title: Ensure systemd-coredump Storage is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - coredump_disable_storage + status: automated + - id: 1.6.1 + title: Ensure /etc/motd is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - cis_banner_text=cis + - banner_etc_motd_cis + status: automated + - id: 1.6.2 + title: Ensure /etc/issue is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - cis_banner_text=cis + - banner_etc_issue_cis + status: automated + - id: 1.6.3 + title: Ensure /etc/issue.net is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - cis_banner_text=cis + - banner_etc_issue_net_cis + status: automated + - id: 1.6.4 + title: Ensure pam_motd is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - pam_motd_configured + status: automated + - id: 1.6.5 + title: Ensure sshd warning Banner is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - cis_banner_text=cis + - banner_etc_issue_net_cis + status: automated + notes: The Level 1 profiles also select sshd_enable_warning_banner_net, which configures /etc/issue.net as the SSH warning + banner. + - id: 1.6.6 + title: Ensure access to /etc/motd is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_etc_motd + - file_owner_etc_motd + - file_permissions_etc_motd + status: automated + - id: 1.6.7 + title: Ensure access to /etc/issue is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_etc_issue + - file_owner_etc_issue + - file_permissions_etc_issue + status: automated + - id: 1.6.8 + title: Ensure access to /etc/issue.net is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_etc_issue_net + - file_owner_etc_issue_net + - file_permissions_etc_issue_net + status: automated + - id: 1.6.9 + title: Ensure access to pam_motd file is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_permissions_pam_motd + status: automated + - id: 1.6.10 + title: Ensure access to sshd warning banner is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_etc_issue_net + - file_owner_etc_issue_net + - file_permissions_etc_issue_net + status: automated + notes: The Level 1 profiles configure /etc/issue.net as the SSH warning banner, so the existing ownership and mode rules + cover the selected banner file. + - id: 1.6.11 + title: Ensure update-notifier-motd.service is not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - service_update-notifier-motd_disabled + status: automated + - id: 1.6.12 + title: Ensure update-notifier-motd.timer is not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - timer_update-notifier-motd_disabled + status: automated + - id: 1.7.1 + title: Ensure GDM login banner is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - dconf_login_banner_text=cis_default + - dconf_login_banner_contents=cis_default + - dconf_gnome_banner_enabled + - dconf_gnome_login_banner_text + status: automated + - id: 1.7.2 + title: Ensure GDM disable-user-list is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - dconf_gnome_disable_user_list + status: automated + - id: 1.7.3 + title: Ensure GDM screen lock is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - inactivity_timeout_value=15_minutes + - var_screensaver_lock_delay=5_seconds + - dconf_gnome_screensaver_idle_delay + - dconf_gnome_screensaver_lock_enabled + - dconf_gnome_screensaver_lock_delay + status: automated + - id: 1.7.4 + title: Ensure GDM automount is configured (Automated) + levels: + - l1_server + - l2_workstation + rules: + - dconf_gnome_disable_automount + - dconf_gnome_disable_automount_open + status: automated + - id: 1.7.5 + title: Ensure GDM autorun-never is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - dconf_gnome_disable_autorun + status: automated + - id: 1.7.6 + title: Ensure XDMCP is not enabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - gnome_gdm_disable_xdmcp + status: automated + - id: 2.1.1 + title: Ensure autofs services are not in use (Automated) + levels: + - l1_server + - l2_workstation + rules: + - service_autofs_disabled + - package_autofs_removed + status: automated + - id: 2.1.2 + title: Ensure avahi daemon services are not in use (Automated) + levels: + - l1_server + - l2_workstation + rules: + - package_avahi_removed + - service_avahi-daemon_disabled + status: automated + - id: 2.1.3 + title: Ensure dhcp server services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_dhcp_removed + - service_dhcpd_disabled + - service_dhcpd6_disabled + status: automated + - id: 2.1.4 + title: Ensure dns server services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_bind_removed + - service_named_disabled + status: automated + - id: 2.1.5 + title: Ensure dnsmasq services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_dnsmasq_removed + - service_dnsmasq_disabled + status: automated + - id: 2.1.6 + title: Ensure ftp server services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_vsftpd_removed + - service_vsftpd_disabled + status: automated + - id: 2.1.7 + title: Ensure ldap server services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_openldap-servers_removed + - service_slapd_disabled + status: automated + - id: 2.1.8 + title: Ensure message access server services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_dovecot_removed + - service_dovecot_disabled + status: automated + - id: 2.1.9 + title: Ensure network file system services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_nfs-kernel-server_removed + - service_nfs_disabled + status: automated + - id: 2.1.10 + title: Ensure nis server services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_ypserv_removed + - service_ypserv_disabled + status: automated + - id: 2.1.11 + title: Ensure print server services are not in use (Automated) + levels: + - l1_server + - l2_workstation + rules: + - package_cups_removed + - service_cups_disabled + status: automated + - id: 2.1.12 + title: Ensure rpcbind services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_rpcbind_removed + - service_rpcbind_disabled + status: automated + - id: 2.1.13 + title: Ensure rsync services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_rsync_removed + - service_rsyncd_disabled + status: automated + - id: 2.1.14 + title: Ensure samba file server services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_samba_removed + - service_smb_disabled + status: automated + - id: 2.1.15 + title: Ensure snmp services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_net-snmp_removed + - service_snmpd_disabled + status: automated + - id: 2.1.16 + title: Ensure telnet server services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_inetutils-telnetd_removed + - package_telnetd_removed + status: automated + - id: 2.1.17 + title: Ensure tftp server services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_tftp-server_removed + - service_tftp_disabled + status: automated + - id: 2.1.18 + title: Ensure web proxy server services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_squid_removed + - service_squid_disabled + status: automated + - id: 2.1.19 + title: Ensure web server services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_httpd_removed + - package_nginx_removed + - service_httpd_disabled + - service_nginx_disabled + status: automated + - id: 2.1.20 + title: Ensure xinetd services are not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_xinetd_removed + - service_xinetd_disabled + status: automated + - id: 2.1.22 + title: Ensure mail transfer agents are configured for local-only mode (Automated) + levels: *l1_both + rules: + - has_nonlocal_mta + - var_postfix_inet_interfaces=loopback-only + - postfix_network_listening_disabled + status: automated + - id: 2.1.23 + title: Ensure only approved services are listening on a network interface (Manual) + levels: *l1_both + status: manual + - id: 2.2.1 + title: Ensure nis client is not installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_nis_removed + status: automated + - id: 2.2.2 + title: Ensure rsh client is not installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_rsh_removed + status: automated + - id: 2.2.3 + title: Ensure talk client is not installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_talk_removed + status: automated + - id: 2.2.4 + title: Ensure telnet client is not installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_inetutils-telnet_removed + - package_telnet_removed + status: automated + - id: 2.2.5 + title: Ensure ldap client is not installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_openldap-clients_removed + status: automated + - id: 2.2.6 + title: Ensure ftp client is not installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_ftp_removed + - package_tnftp_removed + status: automated + - id: 2.3.1.1 + title: Ensure a single time synchronization daemon is in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_timesync_service=chronyd + - package_chrony_installed + - service_chronyd_enabled + - service_chronyd_disabled + - package_timesyncd_installed + - service_timesyncd_enabled + - service_timesyncd_disabled + - ntp_single_service_active + status: automated + notes: | + To select which timesync daemon to install and configure, use the + profile variable var_timesync_service. + - id: 2.3.2.1 + title: Ensure systemd-timesyncd is configured with authorized timeserver (Automated) + levels: *l1_both + rules: + - var_multiple_time_servers=ubuntu + - service_timesyncd_configured + status: automated + - id: 2.3.2.2 + title: Ensure systemd-timesyncd is enabled and running (Automated) + levels: + - l1_server + - l1_workstation + related_rules: + - service_timesyncd_enabled + - service_timesyncd_disabled + status: automated + notes: Implemented in 2.3.1.1 + - id: 2.3.3.1 + title: Ensure chrony is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_multiple_time_servers=ubuntu + - chronyd_specify_remote_server + status: automated + notes: |- + The Ubuntu 26.04 OVAL check follows active sourcedir and confdir + directives and accepts server or pool entries according to site policy. + - id: 2.3.3.2 + title: Ensure chrony is running as user _chrony (Automated) + levels: + - l1_server + - l1_workstation + rules: + - chronyd_run_as_chrony_user + status: automated + - id: 2.3.3.3 + title: Ensure chrony is enabled and running (Automated) + levels: + - l1_server + - l1_workstation + related_rules: + - service_chronyd_enabled + - service_chronyd_disabled + status: automated + notes: Implemented in 2.3.1.1 + - id: 2.4.1.1 + title: Ensure cron daemon is enabled and active (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_cron_installed + - service_cron_enabled + status: automated + - id: 2.4.1.2 + title: Ensure access to /etc/crontab is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_crontab + - file_owner_crontab + - file_permissions_crontab + status: automated + - id: 2.4.1.3 + title: Ensure access to /etc/cron.hourly is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_cron_hourly + - file_owner_cron_hourly + - file_permissions_cron_hourly + status: automated + - id: 2.4.1.4 + title: Ensure access to /etc/cron.daily is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_cron_daily + - file_owner_cron_daily + - file_permissions_cron_daily + status: automated + - id: 2.4.1.5 + title: Ensure access to /etc/cron.weekly is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_cron_weekly + - file_owner_cron_weekly + - file_permissions_cron_weekly + status: automated + - id: 2.4.1.6 + title: Ensure access to /etc/cron.monthly is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_cron_monthly + - file_owner_cron_monthly + - file_permissions_cron_monthly + status: automated + - id: 2.4.1.7 + title: Ensure access to /etc/cron.yearly is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_cron_yearly + - file_owner_cron_yearly + - file_permissions_cron_yearly + status: automated + - id: 2.4.1.8 + title: Ensure access to /etc/cron.d is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_cron_d + - file_owner_cron_d + - file_permissions_cron_d + status: automated + - id: 2.4.1.9 + title: Ensure access to crontab is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_cron_allow_exists + - file_cron_deny_not_exist + - file_groupowner_cron_allow + - file_owner_cron_allow + - file_permissions_cron_allow + status: automated + - id: 2.4.2.1 + title: Ensure access to at is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_at_allow_exists + - file_groupowner_at_allow + - file_owner_at_allow + - file_permissions_at_allow + - file_groupowner_at_deny + - file_owner_at_deny + - file_permissions_at_deny + status: automated + notes: file_owner_at_deny and file_owner_at_allow currently require root as owner and don't accept daemon + - id: 3.1.1 + title: Ensure IPv6 status is identified (Manual) + levels: + - l1_server + - l1_workstation + status: manual + - id: 3.1.2 + title: Ensure wireless interfaces are not available (Automated) + levels: + - l1_server + rules: + - wireless_disable_interfaces + status: automated + - id: 3.1.3 + title: Ensure bluetooth services are not in use (Automated) + levels: + - l1_server + - l2_workstation + rules: + - service_bluetooth_disabled + status: automated + - id: 3.2.1 + title: Ensure atm kernel module is not available (Automated) + levels: + - l1_server + - l1_workstation + rules: + - kernel_module_atm_disabled + status: automated + - id: 3.2.2 + title: Ensure can kernel module is not available (Automated) + levels: + - l1_server + - l1_workstation + rules: + - kernel_module_can_disabled + status: automated + - id: 3.2.3 + title: Ensure dccp kernel module is not available (Automated) + levels: + - l1_server + - l1_workstation + rules: + - kernel_module_dccp_disabled + status: automated + - id: 3.2.4 + title: Ensure rds kernel module is not available (Automated) + levels: + - l1_server + - l1_workstation + rules: + - kernel_module_rds_disabled + status: automated + - id: 3.2.5 + title: Ensure sctp kernel module is not available (Automated) + levels: + - l1_server + - l1_workstation + rules: + - kernel_module_sctp_disabled + status: automated + - id: 3.2.6 + title: Ensure tipc kernel module is not available (Automated) + levels: + - l1_server + - l1_workstation + rules: + - kernel_module_tipc_disabled + status: automated + - id: 3.2.7 + title: Ensure unneeded network protocols are not available (Manual) + levels: *l1_both + status: manual + - id: 3.3.1.1 + title: Ensure net.ipv4.ip_forward is configured (Automated) + levels: + - l1_workstation + - l1_server + rules: + - sysctl_net_ipv4_ip_forward + status: automated + - id: 3.3.1.2 + title: Ensure net.ipv4.conf.all.forwarding is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv4_conf_all_forwarding + status: automated + - id: 3.3.1.3 + title: Ensure net.ipv4.conf.default.forwarding is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv4_conf_default_forwarding + status: automated + - id: 3.3.1.4 + title: Ensure net.ipv4.conf.all.send_redirects is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv4_conf_all_send_redirects + status: automated + - id: 3.3.1.5 + title: Ensure net.ipv4.conf.default.send_redirects is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv4_conf_default_send_redirects + status: automated + - id: 3.3.1.6 + title: Ensure net.ipv4.icmp_ignore_bogus_error_responses is configured (Automated) + levels: *l1_both + rules: + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + status: automated + - id: 3.3.1.7 + title: Ensure net.ipv4.icmp_echo_ignore_broadcasts is configured (Automated) + levels: *l1_both + rules: + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + status: automated + - id: 3.3.1.8 + title: Ensure net.ipv4.conf.all.accept_redirects is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv4_conf_all_accept_redirects + status: automated + - id: 3.3.1.9 + title: Ensure net.ipv4.conf.default.accept_redirects is configured (Automated) + levels: *l1_both + rules: + - sysctl_net_ipv4_conf_default_accept_redirects + status: automated + - id: 3.3.1.10 + title: Ensure net.ipv4.conf.all.secure_redirects is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv4_conf_all_secure_redirects + status: automated + - id: 3.3.1.11 + title: Ensure net.ipv4.conf.default.secure_redirects is configured (Automated) + levels: *l1_both + rules: + - sysctl_net_ipv4_conf_default_secure_redirects + status: automated + - id: 3.3.1.12 + title: Ensure net.ipv4.conf.all.rp_filter is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv4_conf_all_rp_filter + status: automated + - id: 3.3.1.13 + title: Ensure net.ipv4.conf.default.rp_filter is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv4_conf_default_rp_filter + status: automated + - id: 3.3.1.14 + title: Ensure net.ipv4.conf.all.accept_source_route is configured (Automated) + levels: *l1_both + rules: + - sysctl_net_ipv4_conf_all_accept_source_route + status: automated + - id: 3.3.1.15 + title: Ensure net.ipv4.conf.default.accept_source_route is configured (Automated) + levels: *l1_both + rules: + - sysctl_net_ipv4_conf_default_accept_source_route + status: automated + - id: 3.3.1.16 + title: Ensure net.ipv4.conf.all.log_martians is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv4_conf_all_log_martians + status: automated + - id: 3.3.1.17 + title: Ensure net.ipv4.conf.default.log_martians is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv4_conf_default_log_martians + status: automated + notes: See notes for 3.3.1.16. + - id: 3.3.1.18 + title: Ensure net.ipv4.tcp_syncookies is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv4_tcp_syncookies + status: automated + - id: 3.3.1.19 + title: Ensure net.ipv4.conf.all.route_localnet is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv4_conf_all_route_localnet + status: automated + - id: 3.3.2.1 + title: Ensure net.ipv6.conf.all.forwarding is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv6_conf_all_forwarding + status: automated + - id: 3.3.2.2 + title: Ensure net.ipv6.conf.default.forwarding is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv6_conf_default_forwarding + status: automated + - id: 3.3.2.3 + title: Ensure net.ipv6.conf.all.accept_redirects is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv6_conf_all_accept_redirects + status: automated + - id: 3.3.2.4 + title: Ensure net.ipv6.conf.default.accept_redirects is configured (Automated) + levels: *l1_both + rules: + - sysctl_net_ipv6_conf_default_accept_redirects + status: automated + - id: 3.3.2.5 + title: Ensure net.ipv6.conf.all.accept_source_route is configured (Automated) + levels: *l1_both + rules: + - sysctl_net_ipv6_conf_all_accept_source_route + status: automated + - id: 3.3.2.6 + title: Ensure net.ipv6.conf.default.accept_source_route is configured (Automated) + levels: *l1_both + rules: + - sysctl_net_ipv6_conf_default_accept_source_route + status: automated + - id: 3.3.2.7 + title: Ensure net.ipv6.conf.all.accept_ra is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv6_conf_all_accept_ra + status: automated + - id: 3.3.2.8 + title: Ensure net.ipv6.conf.default.accept_ra is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sysctl_net_ipv6_conf_default_accept_ra + status: automated + - id: 4.1.1 + title: Ensure ufw is installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_ufw_installed + status: automated + - id: 4.1.2 + title: Ensure ufw service is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - check_ufw_active + - service_ufw_enabled + status: automated + - id: 4.1.3 + title: Ensure ufw incoming default is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - ufw_default_incoming_rule + status: automated + - id: 4.1.5 + title: Ensure ufw routed default is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - ufw_disabled_routed + status: automated + - id: 5.1.1 + title: Ensure access to /etc/ssh/sshd_config is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_sshd_config + - file_owner_sshd_config + - file_permissions_sshd_config + status: automated + - id: 5.1.2 + title: Ensure access to /etc/ssh/sshd_config.d is configured (Automated) + levels: *l1_both + rules: + - directory_groupowner_sshd_config_d + - directory_owner_sshd_config_d + - directory_permissions_sshd_config_d + status: automated + - id: 5.1.3 + title: Ensure access to SSH private host key files is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_permissions_sshd_private_key + status: automated + - id: 5.1.4 + title: Ensure access to SSH public host key files is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_permissions_sshd_pub_key + status: automated + - id: 5.1.5 + title: Ensure sshd access is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sshd_limit_user_access + status: automated + - id: 5.1.6 + title: Ensure sshd Banner is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sshd_enable_warning_banner_net + status: automated + - id: 5.1.7 + title: Ensure sshd Ciphers are configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sshd_use_strong_ciphers + status: automated + - id: 5.1.8 + title: Ensure sshd ClientAliveInterval and ClientAliveCountMax are configured (Automated) + levels: *l1_both + rules: + - sshd_idle_timeout_value=5_minutes + - var_sshd_set_keepalive=3 + - sshd_set_idle_timeout + - sshd_set_keepalive + status: partial + - id: 5.1.9 + title: Ensure sshd DisableForwarding is enabled (Automated) + levels: + - l1_workstation + - l1_server + rules: + - sshd_disable_forwarding + status: automated + - id: 5.1.10 + title: Ensure sshd GSSAPIAuthentication is disabled (Automated) + levels: + - l1_workstation + - l1_server + rules: + - sshd_disable_gssapi_auth + status: automated + - id: 5.1.11 + title: Ensure sshd HostbasedAuthentication is disabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - disable_host_auth + status: automated + - id: 5.1.12 + title: Ensure sshd IgnoreRhosts is enabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sshd_disable_rhosts + status: automated + - id: 5.1.13 + title: Ensure sshd KexAlgorithms is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sshd_strong_kex=cis_ubuntu2604 + - sshd_use_strong_kex + status: automated + - id: 5.1.14 + title: Ensure sshd post-quantum key exchange algorithms are configured (Manual) + levels: *l1_both + status: manual + - id: 5.1.15 + title: Ensure sshd LoginGraceTime is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_sshd_set_login_grace_time=60 + - sshd_set_login_grace_time + status: automated + - id: 5.1.16 + title: Ensure sshd LogLevel is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sshd_set_loglevel_info + status: automated + - id: 5.1.17 + title: Ensure sshd MACs are configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sshd_strong_macs=cis_ubuntu2404 + - sshd_use_strong_macs + status: automated + - id: 5.1.18 + title: Ensure sshd MaxAuthTries is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sshd_max_auth_tries_value=4 + - sshd_set_max_auth_tries + status: automated + - id: 5.1.19 + title: Ensure sshd MaxSessions is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_sshd_max_sessions=10 + - sshd_set_max_sessions + status: automated + - id: 5.1.20 + title: Ensure sshd MaxStartups is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_sshd_set_maxstartups=10:30:60 + - sshd_set_maxstartups + status: automated + - id: 5.1.21 + title: Ensure sshd PermitEmptyPasswords is disabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sshd_disable_empty_passwords + status: automated + - id: 5.1.22 + title: Ensure sshd PermitRootLogin is disabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sshd_disable_root_login + status: automated + - id: 5.1.23 + title: Ensure sshd PermitUserEnvironment is disabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sshd_do_not_permit_user_env + status: automated + - id: 5.1.24 + title: Ensure sshd UsePAM is enabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sshd_enable_pam + status: automated + - id: 5.2.1 + title: Ensure sudo is installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_sudo_installed + status: automated + - id: 5.2.2 + title: Ensure sudo commands use pty (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sudo_add_use_pty + status: automated + - id: 5.2.3 + title: Ensure sudo log file exists (Automated) + levels: + - l1_server + - l1_workstation + rules: + - sudo_custom_logfile + status: automated + - id: 5.2.5 + title: Ensure users must provide a password for privilege escalation (Automated) + levels: *l1_both + rules: + - sudo_remove_no_authenticate + status: automated + - id: 5.2.6 + title: Ensure sudo timestamp_timeout is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_sudo_timestamp_timeout=15_minutes + - sudo_require_reauthentication + status: automated + - id: 5.2.7 + title: Ensure access to the su command is restricted (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_pam_wheel_group_for_su=cis + - ensure_pam_wheel_group_empty + - use_pam_wheel_group_for_su + status: automated + - id: 5.3.1.1 + title: Ensure latest version of pam is installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_pam_runtime_installed + status: automated + notes: | + The CIS control checks that version >= 1.5.3-5 and not that + it is the latest version as the title suggests. + - id: 5.3.1.2 + title: Ensure latest version of libpam-modules is installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_pam_modules_installed + status: automated + - id: 5.3.1.3 + title: Ensure latest version of libpam-pwquality is installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_pam_pwquality_installed + status: automated + - id: 5.3.1.4 + title: Ensure latest version of cracklib-runtime is installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_cracklib-runtime_installed + status: automated + - id: 5.3.2.1 + title: Ensure pam_unix module is enabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_password_pam_unix_enabled + status: automated + - id: 5.3.2.2 + title: Ensure pam_faillock module is enabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_passwords_pam_faillock_enabled + status: automated + - id: 5.3.2.3 + title: Ensure pam_pwquality module is enabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_password_pam_pwquality_enabled + status: automated + - id: 5.3.2.4 + title: Ensure pam_pwhistory module is enabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_password_pam_pwhistory_enabled + status: automated + - id: 5.3.3.1.1 + title: Ensure password failed attempts lockout is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_accounts_passwords_pam_faillock_deny=4 + - accounts_passwords_pam_faillock_deny + status: automated + - id: 5.3.3.1.2 + title: Ensure password unlock time is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_accounts_passwords_pam_faillock_unlock_time=900 + - accounts_passwords_pam_faillock_unlock_time + status: automated + - id: 5.3.3.2.1 + title: Ensure password number of changed characters is configured (Automated) + levels: *l1_both + rules: + - var_password_pam_difok=2 + - accounts_password_pam_difok + status: automated + - id: 5.3.3.2.2 + title: Ensure password length is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_password_pam_minlen=14 + - accounts_password_pam_minlen + status: automated + - id: 5.3.3.2.3 + title: Ensure password complexity is configured (Manual) + levels: + - l1_server + - l1_workstation + rules: + - var_password_pam_minclass=4 + - var_password_pam_dcredit=1 + - var_password_pam_lcredit=1 + - var_password_pam_ocredit=1 + - var_password_pam_ucredit=1 + - accounts_password_pam_minclass + - accounts_password_pam_dcredit + - accounts_password_pam_lcredit + - accounts_password_pam_ocredit + - accounts_password_pam_ucredit + status: automated + - id: 5.3.3.2.4 + title: Ensure password same consecutive characters is configured (Automated) + levels: *l1_both + rules: + - var_password_pam_maxrepeat=3 + - accounts_password_pam_maxrepeat + status: automated + - id: 5.3.3.2.5 + title: Ensure password maximum sequential characters is configured (Automated) + levels: *l1_both + rules: + - accounts_password_pam_maxsequence + status: automated + - id: 5.3.3.2.6 + title: Ensure password dictionary check is enabled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_password_pam_dictcheck=1 + - accounts_password_pam_dictcheck + status: automated + - id: 5.3.3.2.7 + title: Ensure password quality checking is enforced (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_password_pam_enforcing=1 + - accounts_password_pam_enforcing + status: automated + - id: 5.3.3.2.8 + title: Ensure password quality is enforced for the root user (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_password_pam_enforce_root + status: automated + - id: 5.3.3.3.1 + title: Ensure password history remember is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_password_pam_remember=24 + - accounts_password_pam_pwhistory_remember + status: automated + - id: 5.3.3.3.2 + title: Ensure password history is enforced for the root user (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_password_pam_pwhistory_enforce_root + status: automated + - id: 5.3.3.3.3 + title: Ensure pam_pwhistory includes use_authtok (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_password_pam_pwhistory_use_authtok + status: automated + - id: 5.3.3.4.1 + title: Ensure pam_unix does not include nullok (Automated) + levels: + - l1_server + - l1_workstation + rules: + - no_empty_passwords_unix + status: automated + - id: 5.3.3.4.2 + title: Ensure pam_unix does not include remember (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_password_pam_unix_no_remember + status: automated + - id: 5.3.3.4.3 + title: Ensure pam_unix includes a strong password hashing algorithm (Automated) + levels: *l1_both + rules: + - var_password_hashing_algorithm_pam=yescrypt + - set_password_hashing_algorithm_systemauth + status: automated + - id: 5.3.3.4.4 + title: Ensure pam_unix includes use_authtok (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_password_pam_unix_authtok + status: automated + - id: 5.4.1.1 + title: Ensure password expiration is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_accounts_maximum_age_login_defs=365 + - accounts_maximum_age_login_defs + - accounts_password_set_max_life_existing + status: automated + - id: 5.4.1.3 + title: Ensure password expiration warning days is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_accounts_password_warn_age_login_defs=7 + - accounts_password_warn_age_login_defs + status: automated + - id: 5.4.1.4 + title: Ensure strong password hashing algorithm is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - set_password_hashing_algorithm_logindefs + - var_password_hashing_algorithm=cis_ubuntu2404 + status: automated + notes: Rule allows either SHA512 or YESCRYPT + - id: 5.4.1.5 + title: Ensure inactive password lock is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_account_disable_post_pw_expiration=45 + - account_disable_post_pw_expiration + - accounts_set_post_pw_existing + status: automated + notes: CIS setting now 45 days. + - id: 5.4.1.6 + title: Ensure all users last password change date is in the past (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_password_last_change_is_in_past + status: automated + - id: 5.4.2.1 + title: Ensure root is the only UID 0 account (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_no_uid_except_zero + status: automated + - id: 5.4.2.2 + title: Ensure root is the only GID 0 account (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_root_gid_zero + status: automated + notes: | + The remediation is not automated as the removal or modification + of group IDs from a system is too disruptive. + - id: 5.4.2.3 + title: Ensure group root is the only GID 0 group (Automated) + levels: + - l1_server + - l1_workstation + rules: + - groups_no_zero_gid_except_root + status: automated + notes: | + The remediation is not automated as the removal or modification + of group IDs from a system is too disruptive. + - id: 5.4.2.4 + title: Ensure root account access is controlled (Automated) + levels: + - l1_server + - l1_workstation + rules: + - ensure_root_access_controlled + status: automated + notes: |- + This rule doesn't come with a remediation, as the exact requirement allows root to either + have a password or be locked. + - id: 5.4.2.5 + title: Ensure root path integrity (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_root_path_dirs_no_write + - root_path_all_dirs + - root_path_no_dot + - no_dirs_unowned_by_root + status: automated + - id: 5.4.2.6 + title: Ensure root user umask is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_umask_root + status: automated + - id: 5.4.2.7 + title: Ensure system accounts do not have a valid login shell (Automated) + levels: + - l1_server + - l1_workstation + rules: + - no_shelllogin_for_systemaccounts + status: automated + - id: 5.4.2.8 + title: Ensure accounts without a valid login shell are locked (Automated) + levels: + - l1_server + - l1_workstation + rules: + - no_invalid_shell_accounts_unlocked + status: automated + notes: | + Remediation is not automated. + - id: 5.4.3.2 + title: Ensure default user shell timeout is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_accounts_tmout=15_min + - accounts_tmout + status: automated + - id: 5.4.3.3 + title: Ensure default user umask is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - var_accounts_user_umask=027 + - accounts_umask_etc_bashrc + - accounts_umask_etc_login_defs + - accounts_umask_etc_profile + status: automated + - id: 6.1.1.1.1 + title: Ensure journald service is active (Automated) + levels: + - l1_server + - l1_workstation + rules: + - service_systemd-journald_enabled + status: automated + - id: 6.1.1.1.2 + title: Ensure systemd-journal-remote service is not in use (Automated) + levels: + - l1_server + - l1_workstation + rules: + - socket_systemd-journal-remote_disabled + status: automated + - id: 6.1.1.1.3 + title: Ensure journald is configured to send logs to rsyslog (Automated) + levels: + - l1_server + - l1_workstation + rules: + - journald_forward_to_syslog + status: automated + - id: 6.1.1.1.4 + title: Ensure journald log file access is configured (Manual) + levels: + - l1_server + - l1_workstation + status: manual + - id: 6.1.1.1.5 + title: Ensure journald log file rotation is configured (Manual) + levels: + - l1_server + - l1_workstation + status: manual + - id: 6.1.1.1.6 + title: Ensure journald Storage is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - journald_storage + status: automated + - id: 6.1.1.1.7 + title: Ensure journald Compress is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - journald_compress + status: automated + - id: 6.1.2.1 + title: Ensure rsyslog is installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - package_rsyslog_installed + status: automated + - id: 6.1.2.2 + title: Ensure rsyslog service is enabled and active (Automated) + levels: + - l1_server + - l1_workstation + rules: + - service_rsyslog_enabled + status: automated + - id: 6.1.2.3 + title: Ensure rsyslog log file creation mode is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - rsyslog_filecreatemode + status: automated + - id: 6.1.2.4 + title: Ensure rsyslog logging is configured (Manual) + levels: + - l1_server + - l1_workstation + status: manual + - id: 6.1.2.5 + title: Ensure rsyslog is configured to send logs to a remote log host (Manual) + levels: *l1_both + related_rules: + - rsyslog_remote_loghost + status: manual + - id: 6.1.2.6 + title: Ensure rsyslog is not configured to receive logs from a remote client (Automated) + levels: *l1_both + rules: + - rsyslog_nolisten + status: automated + - id: 6.1.2.7 + title: Ensure logrotate is configured (Manual) + levels: + - l1_server + - l1_workstation + status: manual + - id: 6.1.3.1 + title: Ensure access to all logfiles has been configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupownerships_var_log_apt + - file_groupownerships_var_log_gdm + - file_groupownerships_var_log_gdm3 + - file_groupownerships_var_log_landscape + - file_groupownerships_var_log_sssd + - file_groupowner_var_log_auth + - file_groupowner_var_log_cloud_init + - file_groupowner_var_log_journal + - file_groupowner_var_log_lastlog + - file_groupowner_var_log_localmessages + - file_groupowner_var_log_messages + - file_groupowner_var_log_secure + - file_groupowner_var_log_syslog + - file_groupowner_var_log_waagent + - file_groupowner_var_log_wbtmp + - file_ownerships_var_log_apt + - file_ownerships_var_log_gdm + - file_ownerships_var_log_gdm3 + - file_ownerships_var_log_landscape + - file_ownerships_var_log_sssd + - file_owner_var_log_auth + - file_owner_var_log_cloud_init + - file_owner_var_log_journal + - file_owner_var_log_lastlog + - file_owner_var_log_localmessages + - file_owner_var_log_messages + - file_owner_var_log_secure + - file_owner_var_log_syslog + - file_owner_var_log_waagent + - file_owner_var_log_wbtmp + - file_permissions_var_log_apt + - file_permissions_var_log_auth + - file_permissions_var_log_cloud-init + - file_permissions_var_log_gdm + - file_permissions_var_log_gdm3 + - file_permissions_var_log_lastlog + - file_permissions_var_log_cloud-init + - file_permissions_var_log_localmessages + - file_permissions_var_log_messages + - file_permissions_var_log_secure + - file_permissions_var_log_sssd + - file_permissions_var_log_syslog + - file_permissions_var_log_waagent + - file_permissions_var_log_wbtmp + - file_groupownerships_var_log + - file_ownerships_var_log + - permissions_local_var_log + status: automated + - id: 6.3.1 + title: Ensure AIDE is installed (Automated) + levels: + - l1_server + - l1_workstation + rules: + - aide_build_database + - package_aide_installed + status: automated + - id: 6.3.2 + title: Ensure filesystem integrity is regularly checked (Automated) + levels: + - l1_server + - l1_workstation + rules: + - aide_periodic_checking_systemd_timer + status: automated + - id: 7.1.1 + title: Ensure access to /etc/passwd is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_etc_passwd + - file_owner_etc_passwd + - file_permissions_etc_passwd + status: automated + - id: 7.1.2 + title: Ensure access to /etc/passwd- is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_backup_etc_passwd + - file_owner_backup_etc_passwd + - file_permissions_backup_etc_passwd + status: automated + - id: 7.1.3 + title: Ensure access to /etc/group is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_etc_group + - file_owner_etc_group + - file_permissions_etc_group + status: automated + - id: 7.1.4 + title: Ensure access to /etc/group- is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_backup_etc_group + - file_owner_backup_etc_group + - file_permissions_backup_etc_group + status: automated + - id: 7.1.5 + title: Ensure access to /etc/shadow is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_etc_shadow + - file_owner_etc_shadow + - file_permissions_etc_shadow + status: automated + - id: 7.1.6 + title: Ensure access to /etc/shadow- is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_backup_etc_shadow + - file_owner_backup_etc_shadow + - file_permissions_backup_etc_shadow + status: automated + - id: 7.1.7 + title: Ensure access to /etc/gshadow is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_etc_gshadow + - file_owner_etc_gshadow + - file_permissions_etc_gshadow + status: automated + - id: 7.1.8 + title: Ensure access to /etc/gshadow- is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_groupowner_backup_etc_gshadow + - file_owner_backup_etc_gshadow + - file_permissions_backup_etc_gshadow + status: automated + - id: 7.1.9 + title: Ensure access to /etc/shells is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_owner_etc_shells + - file_groupowner_etc_shells + - file_permissions_etc_shells + status: automated + - id: 7.1.10 + title: Ensure access to /etc/security/opasswd is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_owner_etc_security_opasswd + - file_groupowner_etc_security_opasswd + - file_permissions_etc_security_opasswd + - file_owner_etc_security_opasswd_old + - file_groupowner_etc_security_opasswd_old + - file_permissions_etc_security_opasswd_old + status: automated + - id: 7.1.11 + title: Ensure world writable files and directories are secured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - file_permissions_unauthorized_world_writable + status: automated + - id: 7.1.12 + title: Ensure no files or directories without an owner and a group exist (Automated) + levels: *l1_both + rules: + - no_files_unowned_by_user + - file_permissions_ungroupowned + status: automated + - id: 7.1.13 + title: Ensure SUID and SGID files are reviewed (Manual) + levels: + - l1_server + - l1_workstation + status: manual + - id: 7.2.1 + title: Ensure accounts in /etc/passwd use shadowed passwords (Automated) + levels: + - l1_server + - l1_workstation + rules: + - accounts_password_all_shadowed + status: automated + - id: 7.2.2 + title: Ensure /etc/shadow password fields are not empty (Automated) + levels: + - l1_server + - l1_workstation + rules: + - no_empty_passwords_etc_shadow + status: automated + - id: 7.2.3 + title: Ensure all groups in /etc/passwd exist in /etc/group (Automated) + levels: + - l1_server + - l1_workstation + rules: + - gid_passwd_group_same + status: automated + - id: 7.2.4 + title: Ensure shadow group is empty (Automated) + levels: + - l1_server + - l1_workstation + rules: + - ensure_shadow_group_empty + status: automated + - id: 7.2.5 + title: Ensure no duplicate UIDs exist (Automated) + levels: + - l1_server + - l1_workstation + rules: + - account_unique_id + status: automated + - id: 7.2.6 + title: Ensure no duplicate GIDs exist (Automated) + levels: + - l1_server + - l1_workstation + rules: + - group_unique_id + status: automated + - id: 7.2.7 + title: Ensure no duplicate user names exist (Automated) + levels: + - l1_server + - l1_workstation + rules: + - account_unique_name + status: automated + - id: 7.2.8 + title: Ensure no duplicate group names exist (Automated) + levels: + - l1_server + - l1_workstation + rules: + - group_unique_name + status: automated + - id: 7.2.9 + title: Ensure local interactive user home directories are configured (Automated) + levels: *l1_both + rules: + - accounts_user_interactive_home_directory_exists + - file_groupownership_home_directories + - file_ownership_home_directories + - file_permissions_home_directories + status: automated + - id: 7.2.10 + title: Ensure local interactive user dot files access is configured (Automated) + levels: + - l1_server + - l1_workstation + rules: + - no_rsh_trust_files + - no_forward_files + - no_netrc_files + - accounts_user_dot_user_ownership + - accounts_user_dot_group_ownership + - var_user_initialization_files_regex=all_dotfiles + - file_permission_user_init_files + - file_permission_user_bash_history + status: automated + - id: 7.2.11 + title: Ensure local interactive user dot directories access is configured (Automated) + levels: *l1_both + rules: + - accounts_user_dot_dirs_permissions + - accounts_user_dot_dirs_ownership + - accounts_user_dot_dirs_groupownership + status: automated diff --git a/products/ubuntu2604/profiles/cis_level1_server.profile b/products/ubuntu2604/profiles/cis_level1_server.profile new file mode 100644 index 000000000000..c266000f14d9 --- /dev/null +++ b/products/ubuntu2604/profiles/cis_level1_server.profile @@ -0,0 +1,20 @@ +--- +documentation_complete: true + +metadata: + version: 1.0.0 + +reference: https://www.cisecurity.org/benchmark/ubuntu_linux + +title: 'DRAFT - CIS Ubuntu Linux 26.04 LTS Benchmark for Level 1 - Server' + +description: |- + This draft profile defines a baseline that aligns to the "Level 1 - Server" + configuration from the Center for Internet Security® + Ubuntu Linux 26.04 LTS Benchmark™, v1.0.0, released 2026-08-26. + + This profile includes Center for Internet Security® + Ubuntu Linux 26.04 LTS Benchmark™ content. + +selections: + - cis_ubuntu2604:all:l1_server diff --git a/products/ubuntu2604/profiles/cis_level1_workstation.profile b/products/ubuntu2604/profiles/cis_level1_workstation.profile new file mode 100644 index 000000000000..afd7acced97f --- /dev/null +++ b/products/ubuntu2604/profiles/cis_level1_workstation.profile @@ -0,0 +1,20 @@ +--- +documentation_complete: true + +metadata: + version: 1.0.0 + +reference: https://www.cisecurity.org/benchmark/ubuntu_linux + +title: 'DRAFT - CIS Ubuntu Linux 26.04 LTS Benchmark for Level 1 - Workstation' + +description: |- + This draft profile defines a baseline that aligns to the "Level 1 - Workstation" + configuration from the Center for Internet Security® + Ubuntu Linux 26.04 LTS Benchmark™, v1.0.0, released 2026-08-26. + + This profile includes Center for Internet Security® + Ubuntu Linux 26.04 LTS Benchmark™ content. + +selections: + - cis_ubuntu2604:all:l1_workstation From 3860d2a4874579633b9b30d6414ee4dfa3a41d04 Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 08:53:13 +1200 Subject: [PATCH 02/18] Add Ubuntu 26.04 sshd check adjustments Scope missing_parameter_pass on sshd_disable_empty_passwords to ubuntu2604 so the STIG-mapped presence requirement is preserved on other products. Add ubuntu2604 OVAL overrides for sshd_set_keepalive and sshd_use_strong_kex, and a cis_ubuntu2604 option to sshd_strong_kex.var. --- .../sshd_disable_empty_passwords/rule.yml | 3 +++ .../tests/line_not_there.pass.sh | 17 +++++++++++++++ .../tests/test_config.yml | 2 ++ .../sshd_set_keepalive/oval/ubuntu2604.xml | 21 +++++++++++++++++++ .../sshd_use_strong_kex/oval/ubuntu2604.xml | 20 ++++++++++++++++++ .../guide/services/ssh/sshd_strong_kex.var | 1 + 6 files changed, 64 insertions(+) create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/line_not_there.pass.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/test_config.yml create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive/oval/ubuntu2604.xml create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex/oval/ubuntu2604.xml diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/rule.yml b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/rule.yml index 608f5e6c169b..9ee8162a36bf 100644 --- a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/rule.yml +++ b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/rule.yml @@ -67,3 +67,6 @@ template: value: 'no' datatype: string is_default_value: 'true' +{{% if product in ["ubuntu2604"] %}} + missing_parameter_pass: 'true' +{{% endif %}} diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/line_not_there.pass.sh b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/line_not_there.pass.sh new file mode 100644 index 000000000000..aa7ad21a623e --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/line_not_there.pass.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# platform = multi_platform_ubuntu + +SSHD_PARAM={{{ PARAMETER }}} + +mkdir -p "{{{ sshd_config_dir }}}" +touch "{{{ sshd_config_dir }}}/nothing" +declare -a SSHD_PATHS=({{{ sshd_main_config_file }}} {{{ sshd_config_dir }}}/*) + +{{% if product in ['sle16', 'slmicro6'] %}} +touch "{{{ sshd_main_config_file }}}" +{{% endif %}} + +if grep -q "^\s*${SSHD_PARAM}" "${SSHD_PATHS[@]}" ; then + sed -i "/^\s*${SSHD_PARAM}.*/Id" "${SSHD_PATHS[@]}" +fi diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/test_config.yml b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/test_config.yml new file mode 100644 index 000000000000..998c331c5661 --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/test_config.yml @@ -0,0 +1,2 @@ +deny_templated_scenarios: + - line_not_there.fail.sh diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive/oval/ubuntu2604.xml b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive/oval/ubuntu2604.xml new file mode 100644 index 000000000000..52df8a1259aa --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive/oval/ubuntu2604.xml @@ -0,0 +1,21 @@ +{{%- set sshd_main_config = sshd_main_config_file -%}} + + + {{{ oval_metadata("ClientAliveCountMax is greater than zero, including the compliant OpenSSH default of 3.", rule_title=rule_title) }}} + + + + + + + + + + {{{ sshd_main_config }}}(\.d/.*\.conf)?$ + ^[\s]*(?i)ClientAliveCountMax(?-i)[\s]+0[\s]*(#.*)?$ + 1 + + diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex/oval/ubuntu2604.xml b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex/oval/ubuntu2604.xml new file mode 100644 index 000000000000..4d656f9c723a --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex/oval/ubuntu2604.xml @@ -0,0 +1,20 @@ + + + {{{ oval_metadata("SSH key exchange excludes the algorithms prohibited by CIS Ubuntu 26.04.", rule_title=rule_title) }}} + + + + + + + + + + /etc/ssh/sshd_config(\.d/.*\.conf)?$ + ^[\s]*(?i)KexAlgorithms(?-i)[\s]+(?!-)[^#\n]*(diffie-hellman-group1-sha1|diffie-hellman-group14-sha1|diffie-hellman-group-exchange-sha1)(,|[\s#]|$).*$ + 1 + + diff --git a/linux_os/guide/services/ssh/sshd_strong_kex.var b/linux_os/guide/services/ssh/sshd_strong_kex.var index 38053e889b09..bb6b41d4babe 100644 --- a/linux_os/guide/services/ssh/sshd_strong_kex.var +++ b/linux_os/guide/services/ssh/sshd_strong_kex.var @@ -20,6 +20,7 @@ options: cis_sle15: 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 cis_ubuntu2204: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256 cis_ubuntu2404: sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256 + cis_ubuntu2604: mlkem768x25519-sha256,sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256 std_openeuler: curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 std_kylinsecserver6: curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 cis_debian12: sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256 From dd994ad976b7ad73200f5a1dd990deba99fcd9c7 Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 12:47:16 +1200 Subject: [PATCH 03/18] Clear conflicting APT options during remediation The Acquire::* remediations only removed the option from the file they write, so a conflicting value in /etc/apt/apt.conf or another apt.conf.d file survived. The checks use none_exist across all APT configuration files, so the rules stayed non-compliant after remediation. Strip the option from every APT configuration file before writing the compliant value. Unrelated settings are preserved and the scripts remain idempotent. --- .../bash/shared.sh | 10 +++++++++- .../bash/shared.sh | 10 +++++++++- .../bash/shared.sh | 10 +++++++++- .../apt/apt_configure_check_date/bash/shared.sh | 10 +++++++++- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/bash/shared.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/bash/shared.sh index 946702967ee4..5c96f86f24bc 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/bash/shared.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/bash/shared.sh @@ -5,9 +5,17 @@ # disruption = low config_file=/etc/apt/apt.conf.d/99-cis-repository-security +option='Acquire::AllowDowngradeToInsecureRepositories' setting='Acquire::AllowDowngradeToInsecureRepositories "0";' + touch "$config_file" -sed -ri '/^[[:space:]]*Acquire::AllowDowngradeToInsecureRepositories[[:space:]]+/d' "$config_file" + +# Drop the option everywhere it is already set, so a conflicting value in +# another APT configuration file cannot re-enable it. +while IFS= read -r -d '' apt_conf_file; do + sed -ri "/^[[:space:]]*${option}[[:space:]]+/Id" "$apt_conf_file" +done < <(find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -print0 2>/dev/null) + if [ -s "$config_file" ] && [ -n "$(tail -c 1 "$config_file")" ]; then printf '\n' >> "$config_file" fi diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/bash/shared.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/bash/shared.sh index afe85025241a..13597b578a93 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/bash/shared.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/bash/shared.sh @@ -5,9 +5,17 @@ # disruption = low config_file=/etc/apt/apt.conf.d/99-cis-repository-security +option='Acquire::AllowInsecureRepositories' setting='Acquire::AllowInsecureRepositories "0";' + touch "$config_file" -sed -ri '/^[[:space:]]*Acquire::AllowInsecureRepositories[[:space:]]+/d' "$config_file" + +# Drop the option everywhere it is already set, so a conflicting value in +# another APT configuration file cannot re-enable it. +while IFS= read -r -d '' apt_conf_file; do + sed -ri "/^[[:space:]]*${option}[[:space:]]+/Id" "$apt_conf_file" +done < <(find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -print0 2>/dev/null) + if [ -s "$config_file" ] && [ -n "$(tail -c 1 "$config_file")" ]; then printf '\n' >> "$config_file" fi diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/bash/shared.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/bash/shared.sh index 7a7273cc6d02..a1e0d5d63a54 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/bash/shared.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/bash/shared.sh @@ -5,9 +5,17 @@ # disruption = low config_file=/etc/apt/apt.conf.d/99-cis-repository-security +option='Acquire::AllowWeakRepositories' setting='Acquire::AllowWeakRepositories "0";' + touch "$config_file" -sed -ri '/^[[:space:]]*Acquire::AllowWeakRepositories[[:space:]]+/d' "$config_file" + +# Drop the option everywhere it is already set, so a conflicting value in +# another APT configuration file cannot re-enable it. +while IFS= read -r -d '' apt_conf_file; do + sed -ri "/^[[:space:]]*${option}[[:space:]]+/Id" "$apt_conf_file" +done < <(find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -print0 2>/dev/null) + if [ -s "$config_file" ] && [ -n "$(tail -c 1 "$config_file")" ]; then printf '\n' >> "$config_file" fi diff --git a/linux_os/guide/services/apt/apt_configure_check_date/bash/shared.sh b/linux_os/guide/services/apt/apt_configure_check_date/bash/shared.sh index 5eca2ee6e67c..d79e9a60d1f8 100644 --- a/linux_os/guide/services/apt/apt_configure_check_date/bash/shared.sh +++ b/linux_os/guide/services/apt/apt_configure_check_date/bash/shared.sh @@ -5,9 +5,17 @@ # disruption = low config_file=/etc/apt/apt.conf.d/99-cis-repository-security +option='Acquire::Check-Date' setting='Acquire::Check-Date "true";' + touch "$config_file" -sed -ri '/^[[:space:]]*Acquire::Check-Date[[:space:]]+/d' "$config_file" + +# Drop the option everywhere it is already set, so a conflicting value in +# another APT configuration file cannot re-enable it. +while IFS= read -r -d '' apt_conf_file; do + sed -ri "/^[[:space:]]*${option}[[:space:]]+/Id" "$apt_conf_file" +done < <(find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -print0 2>/dev/null) + if [ -s "$config_file" ] && [ -n "$(tail -c 1 "$config_file")" ]; then printf '\n' >> "$config_file" fi From 9ae2bad00a45dca0796621bb0f366f1177298642 Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 12:47:16 +1200 Subject: [PATCH 04/18] Add test scenarios for the Ubuntu 26.04 CIS rules 47 scenarios covering the 13 new rules. The APT scenarios exercise quoted and unquoted values, case variants, commented settings, deb-src entries, options blocks such as [signed-by=...], and deb822 URIs lines carrying more than one URI. service_update-notifier-motd_disabled ships only a pass scenario. The unit is a static oneshot, so it is never enabled and never lingers active, and the check reports the same result whether or not it has been masked. Recorded in the rule's warnings block. --- .../tests/commented.pass.sh | 8 ++++++++ .../tests/correct_value.pass.sh | 8 ++++++++ .../tests/missing.pass.sh | 9 +++++++++ .../tests/wrong_value.fail.sh | 8 ++++++++ .../tests/wrong_value_unquoted_dir.fail.sh | 9 +++++++++ .../tests/commented.pass.sh | 8 ++++++++ .../tests/correct_value.pass.sh | 8 ++++++++ .../tests/missing.pass.sh | 9 +++++++++ .../tests/wrong_value.fail.sh | 8 ++++++++ .../tests/wrong_value_unquoted_dir.fail.sh | 9 +++++++++ .../tests/commented.pass.sh | 8 ++++++++ .../tests/correct_value.pass.sh | 8 ++++++++ .../tests/missing.pass.sh | 9 +++++++++ .../tests/wrong_value.fail.sh | 8 ++++++++ .../tests/wrong_value_unquoted_dir.fail.sh | 9 +++++++++ .../tests/commented.pass.sh | 8 ++++++++ .../tests/correct_value.pass.sh | 8 ++++++++ .../apt_configure_check_date/tests/missing.pass.sh | 9 +++++++++ .../tests/wrong_value.fail.sh | 8 ++++++++ .../tests/wrong_value_unquoted_dir.fail.sh | 9 +++++++++ .../tests/http_deb822.fail.sh | 10 ++++++++++ .../tests/http_deb822_second_uri.fail.sh | 11 +++++++++++ .../tests/http_legacy_list.fail.sh | 7 +++++++ .../tests/https_only.pass.sh | 10 ++++++++++ .../tests/absent_sources_list.pass.sh | 5 +++++ .../tests/commented_http.pass.sh | 6 ++++++ .../tests/http_deb_src.fail.sh | 6 ++++++ .../apt_sources_list_https/tests/http_entry.fail.sh | 6 ++++++ .../tests/http_entry_with_options.fail.sh | 7 +++++++ .../tests/https_entry.pass.sh | 6 ++++++ .../service_update-notifier-motd_disabled/rule.yml | 8 ++++++++ .../tests/service_masked.pass.sh | 9 +++++++++ .../tests/timer_enabled.fail.sh | 9 +++++++++ .../tests/timer_masked.pass.sh | 10 ++++++++++ .../tests/correct_access.pass.sh | 12 ++++++++++++ .../tests/world_writable.fail.sh | 13 +++++++++++++ .../tests/explicit_safe_motd.pass.sh | 11 +++++++++++ .../tests/motd_discloses_os.fail.sh | 12 ++++++++++++ .../tests/no_explicit_path.fail.sh | 11 +++++++++++ .../tests/expected_owner.pass.sh | 6 ++++++ .../tests/unexpected_owner_system_id.fail.sh | 7 +++++++ .../tests/warning_swapped_group_owners.pass.sh | 11 +++++++++++ .../tests/expected_owner.pass.sh | 6 ++++++ .../tests/unexpected_owner_system_id.fail.sh | 7 +++++++ .../tests/warning_swapped_owners.pass.sh | 11 +++++++++++ .../tests/group_writable_dot_dir.fail.sh | 7 +++++++ .../tests/restrictive_modes.pass.sh | 7 +++++++ .../tests/world_readable_ssh_dir.fail.sh | 7 +++++++ 48 files changed, 406 insertions(+) create mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/commented.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/correct_value.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/missing.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/wrong_value.fail.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/commented.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/correct_value.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/missing.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/wrong_value.fail.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/commented.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/correct_value.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/missing.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/wrong_value.fail.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/wrong_value_unquoted_dir.fail.sh create mode 100644 linux_os/guide/services/apt/apt_configure_check_date/tests/commented.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_check_date/tests/correct_value.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_check_date/tests/missing.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_check_date/tests/wrong_value.fail.sh create mode 100644 linux_os/guide/services/apt/apt_configure_check_date/tests/wrong_value_unquoted_dir.fail.sh create mode 100644 linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_deb822.fail.sh create mode 100644 linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_deb822_second_uri.fail.sh create mode 100644 linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_legacy_list.fail.sh create mode 100644 linux_os/guide/services/apt/apt_sources_list_d_https/tests/https_only.pass.sh create mode 100644 linux_os/guide/services/apt/apt_sources_list_https/tests/absent_sources_list.pass.sh create mode 100644 linux_os/guide/services/apt/apt_sources_list_https/tests/commented_http.pass.sh create mode 100644 linux_os/guide/services/apt/apt_sources_list_https/tests/http_deb_src.fail.sh create mode 100644 linux_os/guide/services/apt/apt_sources_list_https/tests/http_entry.fail.sh create mode 100644 linux_os/guide/services/apt/apt_sources_list_https/tests/http_entry_with_options.fail.sh create mode 100644 linux_os/guide/services/apt/apt_sources_list_https/tests/https_entry.pass.sh create mode 100644 linux_os/guide/services/base/service_update-notifier-motd_disabled/tests/service_masked.pass.sh create mode 100644 linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/timer_enabled.fail.sh create mode 100644 linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/timer_masked.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/correct_access.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/world_writable.fail.sh create mode 100644 linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/explicit_safe_motd.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/motd_discloses_os.fail.sh create mode 100644 linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/no_explicit_path.fail.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/expected_owner.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/unexpected_owner_system_id.fail.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/warning_swapped_group_owners.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/expected_owner.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/unexpected_owner_system_id.fail.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/warning_swapped_owners.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/group_writable_dot_dir.fail.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/restrictive_modes.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/world_readable_ssh_dir.fail.sh diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/commented.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/commented.pass.sh new file mode 100644 index 000000000000..c3976e90a9a1 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/commented.pass.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowDowngradeToInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +echo '# Acquire::AllowDowngradeToInsecureRepositories "1";' >> /etc/apt/apt.conf diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/correct_value.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/correct_value.pass.sh new file mode 100644 index 000000000000..0c9c1bcfaf9d --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/correct_value.pass.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowDowngradeToInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +echo 'Acquire::AllowDowngradeToInsecureRepositories "0";' >> /etc/apt/apt.conf.d/99-cis-repository-security diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/missing.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/missing.pass.sh new file mode 100644 index 000000000000..b1ff491cb0b1 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/missing.pass.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowDowngradeToInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +# The APT default is compliant, so no setting at all must pass. +exit 0 diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/wrong_value.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/wrong_value.fail.sh new file mode 100644 index 000000000000..c97c45ae0c6c --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/wrong_value.fail.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowDowngradeToInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +echo 'Acquire::AllowDowngradeToInsecureRepositories "1";' >> /etc/apt/apt.conf diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh new file mode 100644 index 000000000000..38ceb94237e7 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowDowngradeToInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +# APT option names are case insensitive and values may be unquoted. +echo 'acquire::allowdowngradetoinsecurerepositories 1;' >> /etc/apt/apt.conf.d/70-cac-test diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/commented.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/commented.pass.sh new file mode 100644 index 000000000000..befa67679756 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/commented.pass.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +echo '# Acquire::AllowInsecureRepositories "1";' >> /etc/apt/apt.conf diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/correct_value.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/correct_value.pass.sh new file mode 100644 index 000000000000..ae355514373d --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/correct_value.pass.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +echo 'Acquire::AllowInsecureRepositories "0";' >> /etc/apt/apt.conf.d/99-cis-repository-security diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/missing.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/missing.pass.sh new file mode 100644 index 000000000000..c740f6b54351 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/missing.pass.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +# The APT default is compliant, so no setting at all must pass. +exit 0 diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/wrong_value.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/wrong_value.fail.sh new file mode 100644 index 000000000000..77c0f2a0164e --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/wrong_value.fail.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +echo 'Acquire::AllowInsecureRepositories "1";' >> /etc/apt/apt.conf diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh new file mode 100644 index 000000000000..b88b060c9bed --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +# APT option names are case insensitive and values may be unquoted. +echo 'acquire::allowinsecurerepositories 1;' >> /etc/apt/apt.conf.d/70-cac-test diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/commented.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/commented.pass.sh new file mode 100644 index 000000000000..f01aa2363ab1 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/commented.pass.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowWeakRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +echo '# Acquire::AllowWeakRepositories "1";' >> /etc/apt/apt.conf diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/correct_value.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/correct_value.pass.sh new file mode 100644 index 000000000000..363d600e25aa --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/correct_value.pass.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowWeakRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +echo 'Acquire::AllowWeakRepositories "0";' >> /etc/apt/apt.conf.d/99-cis-repository-security diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/missing.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/missing.pass.sh new file mode 100644 index 000000000000..53e4284d9304 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/missing.pass.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowWeakRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +# The APT default is compliant, so no setting at all must pass. +exit 0 diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/wrong_value.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/wrong_value.fail.sh new file mode 100644 index 000000000000..17f2d12aa1f7 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/wrong_value.fail.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowWeakRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +echo 'Acquire::AllowWeakRepositories "1";' >> /etc/apt/apt.conf diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/wrong_value_unquoted_dir.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/wrong_value_unquoted_dir.fail.sh new file mode 100644 index 000000000000..fc5cbb7cb27c --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/wrong_value_unquoted_dir.fail.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowWeakRepositories[[:space:]]+/Id' {} + 2>/dev/null || true + +# APT option names are case insensitive and values may be unquoted. +echo 'acquire::allowweakrepositories 1;' >> /etc/apt/apt.conf.d/70-cac-test diff --git a/linux_os/guide/services/apt/apt_configure_check_date/tests/commented.pass.sh b/linux_os/guide/services/apt/apt_configure_check_date/tests/commented.pass.sh new file mode 100644 index 000000000000..1b9241252b27 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_check_date/tests/commented.pass.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::Check-Date[[:space:]]+/Id' {} + 2>/dev/null || true + +echo '# Acquire::Check-Date "false";' >> /etc/apt/apt.conf diff --git a/linux_os/guide/services/apt/apt_configure_check_date/tests/correct_value.pass.sh b/linux_os/guide/services/apt/apt_configure_check_date/tests/correct_value.pass.sh new file mode 100644 index 000000000000..25bb94b98d42 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_check_date/tests/correct_value.pass.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::Check-Date[[:space:]]+/Id' {} + 2>/dev/null || true + +echo 'Acquire::Check-Date "true";' >> /etc/apt/apt.conf.d/99-cis-repository-security diff --git a/linux_os/guide/services/apt/apt_configure_check_date/tests/missing.pass.sh b/linux_os/guide/services/apt/apt_configure_check_date/tests/missing.pass.sh new file mode 100644 index 000000000000..ca24879e28ae --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_check_date/tests/missing.pass.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::Check-Date[[:space:]]+/Id' {} + 2>/dev/null || true + +# The APT default is compliant, so no setting at all must pass. +exit 0 diff --git a/linux_os/guide/services/apt/apt_configure_check_date/tests/wrong_value.fail.sh b/linux_os/guide/services/apt/apt_configure_check_date/tests/wrong_value.fail.sh new file mode 100644 index 000000000000..f7a7078c6625 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_check_date/tests/wrong_value.fail.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::Check-Date[[:space:]]+/Id' {} + 2>/dev/null || true + +echo 'Acquire::Check-Date "false";' >> /etc/apt/apt.conf diff --git a/linux_os/guide/services/apt/apt_configure_check_date/tests/wrong_value_unquoted_dir.fail.sh b/linux_os/guide/services/apt/apt_configure_check_date/tests/wrong_value_unquoted_dir.fail.sh new file mode 100644 index 000000000000..18786c1daf50 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_check_date/tests/wrong_value_unquoted_dir.fail.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::Check-Date[[:space:]]+/Id' {} + 2>/dev/null || true + +# APT option names are case insensitive and values may be unquoted. +echo 'acquire::check-date false;' >> /etc/apt/apt.conf.d/70-cac-test diff --git a/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_deb822.fail.sh b/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_deb822.fail.sh new file mode 100644 index 000000000000..a9d75e8ac706 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_deb822.fail.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +find /etc/apt/sources.list.d -maxdepth 1 -type f \( -name '*.list' -o -name '*.sources' \) -exec sed -ri 's#http://#https://#g' {} + 2>/dev/null || true +cat > /etc/apt/sources.list.d/cac-test.sources <<'EOF' +Types: deb +URIs: http://archive.ubuntu.com/ubuntu +Suites: resolute +Components: main +EOF diff --git a/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_deb822_second_uri.fail.sh b/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_deb822_second_uri.fail.sh new file mode 100644 index 000000000000..5b02008dbb51 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_deb822_second_uri.fail.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +find /etc/apt/sources.list.d -maxdepth 1 -type f \( -name '*.list' -o -name '*.sources' \) -exec sed -ri 's#http://#https://#g' {} + 2>/dev/null || true +# A URIs line may carry several URIs; an http:// one after an https:// one still counts. +cat > /etc/apt/sources.list.d/cac-test.sources <<'EOF' +Types: deb +URIs: https://archive.ubuntu.com/ubuntu http://security.ubuntu.com/ubuntu +Suites: resolute +Components: main +EOF diff --git a/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_legacy_list.fail.sh b/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_legacy_list.fail.sh new file mode 100644 index 000000000000..2cd769146e6f --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_legacy_list.fail.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +find /etc/apt/sources.list.d -maxdepth 1 -type f \( -name '*.list' -o -name '*.sources' \) -exec sed -ri 's#http://#https://#g' {} + 2>/dev/null || true +cat > /etc/apt/sources.list.d/cac-test.list <<'EOF' +deb [arch=amd64] http://archive.ubuntu.com/ubuntu resolute main +EOF diff --git a/linux_os/guide/services/apt/apt_sources_list_d_https/tests/https_only.pass.sh b/linux_os/guide/services/apt/apt_sources_list_d_https/tests/https_only.pass.sh new file mode 100644 index 000000000000..d0b3e1f49e01 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_d_https/tests/https_only.pass.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +find /etc/apt/sources.list.d -maxdepth 1 -type f \( -name '*.list' -o -name '*.sources' \) -exec sed -ri 's#http://#https://#g' {} + 2>/dev/null || true +cat > /etc/apt/sources.list.d/cac-test.sources <<'EOF' +Types: deb +URIs: https://archive.ubuntu.com/ubuntu +Suites: resolute +Components: main +EOF diff --git a/linux_os/guide/services/apt/apt_sources_list_https/tests/absent_sources_list.pass.sh b/linux_os/guide/services/apt/apt_sources_list_https/tests/absent_sources_list.pass.sh new file mode 100644 index 000000000000..f056d78ccd25 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_https/tests/absent_sources_list.pass.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +# Ubuntu 26.04 uses deb822 and ships no /etc/apt/sources.list at all. +rm -f /etc/apt/sources.list diff --git a/linux_os/guide/services/apt/apt_sources_list_https/tests/commented_http.pass.sh b/linux_os/guide/services/apt/apt_sources_list_https/tests/commented_http.pass.sh new file mode 100644 index 000000000000..f723af74e86c --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_https/tests/commented_http.pass.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +cat > /etc/apt/sources.list <<'EOF' +# deb http://archive.ubuntu.com/ubuntu resolute main +EOF diff --git a/linux_os/guide/services/apt/apt_sources_list_https/tests/http_deb_src.fail.sh b/linux_os/guide/services/apt/apt_sources_list_https/tests/http_deb_src.fail.sh new file mode 100644 index 000000000000..4d9600c08e24 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_https/tests/http_deb_src.fail.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +cat > /etc/apt/sources.list <<'EOF' +deb-src http://archive.ubuntu.com/ubuntu resolute main +EOF diff --git a/linux_os/guide/services/apt/apt_sources_list_https/tests/http_entry.fail.sh b/linux_os/guide/services/apt/apt_sources_list_https/tests/http_entry.fail.sh new file mode 100644 index 000000000000..5cca2064bd3f --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_https/tests/http_entry.fail.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +cat > /etc/apt/sources.list <<'EOF' +deb http://archive.ubuntu.com/ubuntu resolute main +EOF diff --git a/linux_os/guide/services/apt/apt_sources_list_https/tests/http_entry_with_options.fail.sh b/linux_os/guide/services/apt/apt_sources_list_https/tests/http_entry_with_options.fail.sh new file mode 100644 index 000000000000..2341c0b19205 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_https/tests/http_entry_with_options.fail.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +# An options block between deb and the URI must not hide the http:// entry. +cat > /etc/apt/sources.list <<'EOF' +deb [signed-by=/usr/share/keyrings/ubuntu-archive-keyring.gpg] http://archive.ubuntu.com/ubuntu resolute main +EOF diff --git a/linux_os/guide/services/apt/apt_sources_list_https/tests/https_entry.pass.sh b/linux_os/guide/services/apt/apt_sources_list_https/tests/https_entry.pass.sh new file mode 100644 index 000000000000..7c429ed4bf18 --- /dev/null +++ b/linux_os/guide/services/apt/apt_sources_list_https/tests/https_entry.pass.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +cat > /etc/apt/sources.list <<'EOF' +deb https://archive.ubuntu.com/ubuntu resolute main +EOF diff --git a/linux_os/guide/services/base/service_update-notifier-motd_disabled/rule.yml b/linux_os/guide/services/base/service_update-notifier-motd_disabled/rule.yml index 3bdd78bdb8c7..5f07963aa979 100644 --- a/linux_os/guide/services/base/service_update-notifier-motd_disabled/rule.yml +++ b/linux_os/guide/services/base/service_update-notifier-motd_disabled/rule.yml @@ -13,3 +13,11 @@ rationale: |- severity: medium platform: system_with_kernel + +warnings: + - general: |- + update-notifier-motd.service is a static, oneshot unit triggered by + update-notifier-motd.timer. A static unit cannot be enabled, and a oneshot + unit is inactive except while it runs, so this check reports the same result + whether or not the unit has been masked. The timer rule is what detects the + MOTD updates actually being in use. diff --git a/linux_os/guide/services/base/service_update-notifier-motd_disabled/tests/service_masked.pass.sh b/linux_os/guide/services/base/service_update-notifier-motd_disabled/tests/service_masked.pass.sh new file mode 100644 index 000000000000..d32709976e2d --- /dev/null +++ b/linux_os/guide/services/base/service_update-notifier-motd_disabled/tests/service_masked.pass.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# packages = update-notifier-common + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if "$SYSTEMCTL_EXEC" -q list-unit-files 'update-notifier-motd.service'; then + "$SYSTEMCTL_EXEC" stop 'update-notifier-motd.service' + "$SYSTEMCTL_EXEC" mask 'update-notifier-motd.service' +fi +"$SYSTEMCTL_EXEC" reset-failed 'update-notifier-motd.service' || true diff --git a/linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/timer_enabled.fail.sh b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/timer_enabled.fail.sh new file mode 100644 index 000000000000..33792a99cfc2 --- /dev/null +++ b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/timer_enabled.fail.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# packages = update-notifier-common + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if "$SYSTEMCTL_EXEC" -q list-unit-files 'update-notifier-motd.timer'; then + "$SYSTEMCTL_EXEC" unmask 'update-notifier-motd.timer' + "$SYSTEMCTL_EXEC" enable 'update-notifier-motd.timer' + "$SYSTEMCTL_EXEC" start 'update-notifier-motd.timer' +fi diff --git a/linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/timer_masked.pass.sh b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/timer_masked.pass.sh new file mode 100644 index 000000000000..9abf51f2503a --- /dev/null +++ b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/timer_masked.pass.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# packages = update-notifier-common + +SYSTEMCTL_EXEC='/usr/bin/systemctl' +if "$SYSTEMCTL_EXEC" -q list-unit-files 'update-notifier-motd.timer'; then + "$SYSTEMCTL_EXEC" stop 'update-notifier-motd.timer' + "$SYSTEMCTL_EXEC" disable 'update-notifier-motd.timer' + "$SYSTEMCTL_EXEC" mask 'update-notifier-motd.timer' +fi +"$SYSTEMCTL_EXEC" reset-failed 'update-notifier-motd.timer' || true diff --git a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/correct_access.pass.sh b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/correct_access.pass.sh new file mode 100644 index 000000000000..21d8a166e285 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/correct_access.pass.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +# Remove every pam_motd entry the check looks at, so each scenario starts clean. +for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/su /etc/pam.d/gdm-password; do + [ -f "$f" ] && sed -ri '/pam_motd\.so/d' "$f" +done + +printf 'Authorized use only.\n' > /etc/motd.cac +chown root:root /etc/motd.cac +chmod 0644 /etc/motd.cac +echo 'session optional pam_motd.so motd=/etc/motd.cac' >> /etc/pam.d/sshd diff --git a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/world_writable.fail.sh b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/world_writable.fail.sh new file mode 100644 index 000000000000..3c938493466f --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/world_writable.fail.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# platform = multi_platform_ubuntu +# remediation = none + +# Remove every pam_motd entry the check looks at, so each scenario starts clean. +for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/su /etc/pam.d/gdm-password; do + [ -f "$f" ] && sed -ri '/pam_motd\.so/d' "$f" +done + +printf 'Authorized use only.\n' > /etc/motd.cac +chown root:root /etc/motd.cac +chmod 0666 /etc/motd.cac +echo 'session optional pam_motd.so motd=/etc/motd.cac' >> /etc/pam.d/sshd diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/explicit_safe_motd.pass.sh b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/explicit_safe_motd.pass.sh new file mode 100644 index 000000000000..3cee8e3aac18 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/explicit_safe_motd.pass.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +# Remove every pam_motd entry the check looks at, so each scenario starts clean. +for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/su /etc/pam.d/gdm-password; do + [ -f "$f" ] && sed -ri '/pam_motd\.so/d' "$f" +done + +printf 'Authorized use only. All activity may be monitored.\n' > /etc/motd.cac +chmod 0644 /etc/motd.cac +echo 'session optional pam_motd.so motd=/etc/motd.cac' >> /etc/pam.d/sshd diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/motd_discloses_os.fail.sh b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/motd_discloses_os.fail.sh new file mode 100644 index 000000000000..ffeeda3b5aeb --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/motd_discloses_os.fail.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# platform = multi_platform_ubuntu +# remediation = none + +# Remove every pam_motd entry the check looks at, so each scenario starts clean. +for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/su /etc/pam.d/gdm-password; do + [ -f "$f" ] && sed -ri '/pam_motd\.so/d' "$f" +done + +printf 'Welcome to Ubuntu\n' > /etc/motd.cac +chmod 0644 /etc/motd.cac +echo 'session optional pam_motd.so motd=/etc/motd.cac' >> /etc/pam.d/sshd diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/no_explicit_path.fail.sh b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/no_explicit_path.fail.sh new file mode 100644 index 000000000000..08263446eef2 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/no_explicit_path.fail.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# platform = multi_platform_ubuntu +# remediation = none + +# Remove every pam_motd entry the check looks at, so each scenario starts clean. +for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/su /etc/pam.d/gdm-password; do + [ -f "$f" ] && sed -ri '/pam_motd\.so/d' "$f" +done + +# pam_motd is used but no explicit motd= path is given. +echo 'session optional pam_motd.so noupdate' >> /etc/pam.d/sshd diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/expected_owner.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/expected_owner.pass.sh new file mode 100644 index 000000000000..cb41b9bb97d3 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/expected_owner.pass.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +USER="cac_user" +useradd -m $USER +mkdir -p /home/$USER/.config +chgrp -R "$(id -g $USER)" /home/$USER/.config diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/unexpected_owner_system_id.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/unexpected_owner_system_id.fail.sh new file mode 100644 index 000000000000..fca8df3db0d3 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/unexpected_owner_system_id.fail.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# remediation = none + +USER="cac_user" +useradd -m $USER +mkdir -p /home/$USER/.config +chgrp -R 2 /home/$USER/.config diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/warning_swapped_group_owners.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/warning_swapped_group_owners.pass.sh new file mode 100644 index 000000000000..c6c720bfa631 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/warning_swapped_group_owners.pass.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Documents the limitation recorded in the rule's warnings block: a dot directory +# belonging to one interactive user but group ownered by another still passes, because the +# check only requires an interactive user's id. +USER1="cac_user1" +USER2="cac_user2" +useradd -m $USER1 +useradd -m $USER2 +mkdir -p /home/$USER1/.config +chgrp -R "$(id -g $USER2)" /home/$USER1/.config diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/expected_owner.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/expected_owner.pass.sh new file mode 100644 index 000000000000..88a611cd014b --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/expected_owner.pass.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +USER="cac_user" +useradd -m $USER +mkdir -p /home/$USER/.config +chown -R $USER /home/$USER/.config diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/unexpected_owner_system_id.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/unexpected_owner_system_id.fail.sh new file mode 100644 index 000000000000..37d4a1a8bcaf --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/unexpected_owner_system_id.fail.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# remediation = none + +USER="cac_user" +useradd -m $USER +mkdir -p /home/$USER/.config +chown -R 2 /home/$USER/.config diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/warning_swapped_owners.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/warning_swapped_owners.pass.sh new file mode 100644 index 000000000000..1db07c618cba --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/warning_swapped_owners.pass.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# Documents the limitation recorded in the rule's warnings block: a dot directory +# belonging to one interactive user but ownered by another still passes, because the +# check only requires an interactive user's id. +USER1="cac_user1" +USER2="cac_user2" +useradd -m $USER1 +useradd -m $USER2 +mkdir -p /home/$USER1/.config +chown -R $USER2 /home/$USER1/.config diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/group_writable_dot_dir.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/group_writable_dot_dir.fail.sh new file mode 100644 index 000000000000..9b5623c31149 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/group_writable_dot_dir.fail.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# remediation = none + +USER="cac_user" +useradd -m $USER +mkdir -p /home/$USER/.config +chmod 0770 /home/$USER/.config diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/restrictive_modes.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/restrictive_modes.pass.sh new file mode 100644 index 000000000000..8b5f7e7fdf53 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/restrictive_modes.pass.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +USER="cac_user" +useradd -m $USER +mkdir -p /home/$USER/.config /home/$USER/.ssh +chmod 0750 /home/$USER/.config +chmod 0700 /home/$USER/.ssh diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/world_readable_ssh_dir.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/world_readable_ssh_dir.fail.sh new file mode 100644 index 000000000000..85adf1bdd908 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/world_readable_ssh_dir.fail.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# remediation = none + +USER="cac_user" +useradd -m $USER +mkdir -p /home/$USER/.ssh +chmod 0755 /home/$USER/.ssh From 5df932af10feb28676fef6c20a283b0ba5143e6c Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 15:29:30 +1200 Subject: [PATCH 05/18] Enable SCE checks for Ubuntu 26.04 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c58ed4c74078..69628878da70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,7 +151,7 @@ find_program(XMLLINT_EXECUTABLE NAMES xmllint REQUIRED) find_program(XSLTPROC_EXECUTABLE NAMES xsltproc REQUIRED) find_program(YAMLLINT_EXECUTABLE NAMES yamllint) -if(SSG_PRODUCT_FEDORA OR SSG_PRODUCT_RHEL8 OR SSG_PRODUCT_RHEL9 OR SSG_PRODUCT_RHEL10 OR SSG_PRODUCT_UBUNTU2004 OR SSG_PRODUCT_UBUNTU2204 OR SSG_PRODUCT_UBUNTU2404) +if(SSG_PRODUCT_FEDORA OR SSG_PRODUCT_RHEL8 OR SSG_PRODUCT_RHEL9 OR SSG_PRODUCT_RHEL10 OR SSG_PRODUCT_UBUNTU2004 OR SSG_PRODUCT_UBUNTU2204 OR SSG_PRODUCT_UBUNTU2404 OR SSG_PRODUCT_UBUNTU2604) set(SSG_SCE_ENABLED ON) endif() From 354f2711accb7094763ebcf2387bb105990fda9c Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 15:29:30 +1200 Subject: [PATCH 06/18] Fix APT policy evaluation for Ubuntu 26.04 --- .../bash/shared.sh | 7 ++++--- .../oval/shared.xml | 17 ----------------- .../rule.yml | 2 +- .../sce/shared.sh | 17 +++++++++++++++++ ...commented.pass.sh => commented_only.fail.sh} | 3 +-- .../tests/missing.fail.sh} | 5 +---- .../tests/missing.pass.sh | 9 --------- .../tests/nested_correct_value.pass.sh | 5 +++++ .../tests/nested_wrong_value.fail.sh | 5 +++++ .../tests/wrong_value_unquoted_dir.fail.sh | 2 +- .../bash/shared.sh | 7 ++++--- .../oval/shared.xml | 17 ----------------- .../rule.yml | 3 ++- .../sce/shared.sh | 17 +++++++++++++++++ ...commented.pass.sh => commented_only.fail.sh} | 3 +-- .../tests/missing.fail.sh | 6 ++++++ .../tests/missing.pass.sh | 9 --------- .../tests/nested_correct_value.pass.sh | 5 +++++ .../tests/nested_wrong_value.fail.sh | 5 +++++ .../tests/wrong_value_unquoted_dir.fail.sh | 2 +- .../bash/shared.sh | 7 ++++--- .../oval/shared.xml | 17 ----------------- .../rule.yml | 3 ++- .../sce/shared.sh | 17 +++++++++++++++++ ...commented.pass.sh => commented_only.fail.sh} | 3 +-- .../tests/missing.fail.sh | 6 ++++++ .../tests/missing.pass.sh | 9 --------- .../tests/nested_correct_value.pass.sh | 5 +++++ .../tests/nested_wrong_value.fail.sh | 5 +++++ .../tests/wrong_value_unquoted_dir.fail.sh | 2 +- .../apt/apt_configure_check_date/bash/shared.sh | 7 ++++--- .../apt_configure_check_date/oval/shared.xml | 17 ----------------- .../apt/apt_configure_check_date/rule.yml | 3 ++- .../apt/apt_configure_check_date/sce/shared.sh | 17 +++++++++++++++++ ...commented.pass.sh => commented_only.fail.sh} | 3 +-- .../tests/missing.fail.sh | 6 ++++++ .../tests/nested_correct_value.pass.sh | 5 +++++ .../tests/nested_wrong_value.fail.sh | 5 +++++ .../tests/wrong_value_unquoted_dir.fail.sh | 2 +- .../tests/http_deb822_second_uri.fail.sh | 2 +- .../tests/absent_sources_list.pass.sh | 2 +- .../tests/http_entry_with_options.fail.sh | 2 +- 42 files changed, 161 insertions(+), 130 deletions(-) delete mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/oval/shared.xml create mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/sce/shared.sh rename linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/{commented.pass.sh => commented_only.fail.sh} (67%) rename linux_os/guide/services/apt/{apt_configure_check_date/tests/missing.pass.sh => apt_configure_allow_downgrade_to_insecure_repositories/tests/missing.fail.sh} (50%) delete mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/missing.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/nested_correct_value.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/nested_wrong_value.fail.sh delete mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/oval/shared.xml create mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/sce/shared.sh rename linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/{commented.pass.sh => commented_only.fail.sh} (68%) create mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/missing.fail.sh delete mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/missing.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/nested_correct_value.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/nested_wrong_value.fail.sh delete mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/oval/shared.xml create mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/sce/shared.sh rename linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/{commented.pass.sh => commented_only.fail.sh} (69%) create mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/missing.fail.sh delete mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/missing.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/nested_correct_value.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/nested_wrong_value.fail.sh delete mode 100644 linux_os/guide/services/apt/apt_configure_check_date/oval/shared.xml create mode 100644 linux_os/guide/services/apt/apt_configure_check_date/sce/shared.sh rename linux_os/guide/services/apt/apt_configure_check_date/tests/{commented.pass.sh => commented_only.fail.sh} (70%) create mode 100644 linux_os/guide/services/apt/apt_configure_check_date/tests/missing.fail.sh create mode 100644 linux_os/guide/services/apt/apt_configure_check_date/tests/nested_correct_value.pass.sh create mode 100644 linux_os/guide/services/apt/apt_configure_check_date/tests/nested_wrong_value.fail.sh diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/bash/shared.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/bash/shared.sh index 5c96f86f24bc..b04f33f0124b 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/bash/shared.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/bash/shared.sh @@ -6,14 +6,15 @@ config_file=/etc/apt/apt.conf.d/99-cis-repository-security option='Acquire::AllowDowngradeToInsecureRepositories' +option_pattern='(Acquire::)?AllowDowngradeToInsecureRepositories' setting='Acquire::AllowDowngradeToInsecureRepositories "0";' touch "$config_file" -# Drop the option everywhere it is already set, so a conflicting value in -# another APT configuration file cannot re-enable it. +# Remove existing definitions before writing the required value. Otherwise, +# APT file precedence could leave a conflicting definition in effect. while IFS= read -r -d '' apt_conf_file; do - sed -ri "/^[[:space:]]*${option}[[:space:]]+/Id" "$apt_conf_file" + sed -ri "/^[[:space:]]*${option_pattern}[[:space:]]+/Id" "$apt_conf_file" done < <(find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -print0 2>/dev/null) if [ -s "$config_file" ] && [ -n "$(tail -c 1 "$config_file")" ]; then diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/oval/shared.xml b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/oval/shared.xml deleted file mode 100644 index b99a2f91051c..000000000000 --- a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/oval/shared.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - {{{ oval_metadata("APT does not allow downgrade to insecure repositories.", rule_title=rule_title) }}} - - - - - - - - - /etc/apt/apt\.conf(\.d/.*)?$ - ^[\s]*(?i)Acquire::AllowDowngradeToInsecureRepositories(?-i)[\s]+"?(?i)(1|true|yes|with|on)(?-i)"?[\s]*;[\s]*(#.*)?$ - 1 - - diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/rule.yml b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/rule.yml index e92b7b33eab9..2d403339f0d8 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/rule.yml +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/rule.yml @@ -3,7 +3,7 @@ documentation_complete: true title: 'Disable APT AllowDowngradeToInsecureRepositories' description: |- - Configure APT with + Configure the effective APT setting with Acquire::AllowDowngradeToInsecureRepositories "0";. rationale: |- diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/sce/shared.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/sce/shared.sh new file mode 100644 index 000000000000..b0f07ad6ec38 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/sce/shared.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# platform = multi_platform_ubuntu +# check-import = stdout + +explicit=false +for config_file in /etc/apt/apt.conf /etc/apt/apt.conf.d/*; do + [[ -f "$config_file" ]] || continue + [[ "$config_file" == /etc/apt/apt.conf || ${config_file##*/} =~ ^[A-Za-z0-9_-]+$ ]] || continue + grep -Piq '^[\h]*(Acquire::)?AllowDowngradeToInsecureRepositories\h+' "$config_file" && explicit=true +done + +if [[ "$explicit" == true ]] && apt-config dump 2>/dev/null | grep -Piq '^Acquire::AllowDowngradeToInsecureRepositories\s+"?(0|false|no|without|off)"?;$'; then + exit "$XCCDF_RESULT_PASS" +fi + +echo 'Acquire::AllowDowngradeToInsecureRepositories is not explicitly configured with a disabled value.' +exit "$XCCDF_RESULT_FAIL" diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/commented.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/commented_only.fail.sh similarity index 67% rename from linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/commented.pass.sh rename to linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/commented_only.fail.sh index c3976e90a9a1..6e9f4ab5ef06 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/commented.pass.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/commented_only.fail.sh @@ -3,6 +3,5 @@ mkdir -p /etc/apt/apt.conf.d touch /etc/apt/apt.conf -find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowDowngradeToInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true - +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*(Acquire::)?AllowDowngradeToInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true echo '# Acquire::AllowDowngradeToInsecureRepositories "1";' >> /etc/apt/apt.conf diff --git a/linux_os/guide/services/apt/apt_configure_check_date/tests/missing.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/missing.fail.sh similarity index 50% rename from linux_os/guide/services/apt/apt_configure_check_date/tests/missing.pass.sh rename to linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/missing.fail.sh index ca24879e28ae..9991fca61917 100644 --- a/linux_os/guide/services/apt/apt_configure_check_date/tests/missing.pass.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/missing.fail.sh @@ -3,7 +3,4 @@ mkdir -p /etc/apt/apt.conf.d touch /etc/apt/apt.conf -find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::Check-Date[[:space:]]+/Id' {} + 2>/dev/null || true - -# The APT default is compliant, so no setting at all must pass. -exit 0 +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*(Acquire::)?AllowDowngradeToInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/missing.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/missing.pass.sh deleted file mode 100644 index b1ff491cb0b1..000000000000 --- a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/missing.pass.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# platform = multi_platform_ubuntu - -mkdir -p /etc/apt/apt.conf.d -touch /etc/apt/apt.conf -find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowDowngradeToInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true - -# The APT default is compliant, so no setting at all must pass. -exit 0 diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/nested_correct_value.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/nested_correct_value.pass.sh new file mode 100644 index 000000000000..71756189a850 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/nested_correct_value.pass.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = Ubuntu 26.04 + +mkdir -p /etc/apt/apt.conf.d +printf '%s\n' 'Acquire {' ' AllowDowngradeToInsecureRepositories "0";' '};' > /etc/apt/apt.conf.d/99-cis-repository-security diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/nested_wrong_value.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/nested_wrong_value.fail.sh new file mode 100644 index 000000000000..828edcb25933 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/nested_wrong_value.fail.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +printf '%s\n' 'Acquire {' ' AllowDowngradeToInsecureRepositories "1";' '};' > /etc/apt/apt.conf.d/70-cac-test diff --git a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh index 38ceb94237e7..efd08c782bfa 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_downgrade_to_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh @@ -5,5 +5,5 @@ mkdir -p /etc/apt/apt.conf.d touch /etc/apt/apt.conf find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowDowngradeToInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true -# APT option names are case insensitive and values may be unquoted. +# APT accepts case-insensitive option names and unquoted values. echo 'acquire::allowdowngradetoinsecurerepositories 1;' >> /etc/apt/apt.conf.d/70-cac-test diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/bash/shared.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/bash/shared.sh index 13597b578a93..bcc66984ba25 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/bash/shared.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/bash/shared.sh @@ -6,14 +6,15 @@ config_file=/etc/apt/apt.conf.d/99-cis-repository-security option='Acquire::AllowInsecureRepositories' +option_pattern='(Acquire::)?AllowInsecureRepositories' setting='Acquire::AllowInsecureRepositories "0";' touch "$config_file" -# Drop the option everywhere it is already set, so a conflicting value in -# another APT configuration file cannot re-enable it. +# Remove existing definitions before writing the required value. Otherwise, +# APT file precedence could leave a conflicting definition in effect. while IFS= read -r -d '' apt_conf_file; do - sed -ri "/^[[:space:]]*${option}[[:space:]]+/Id" "$apt_conf_file" + sed -ri "/^[[:space:]]*${option_pattern}[[:space:]]+/Id" "$apt_conf_file" done < <(find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -print0 2>/dev/null) if [ -s "$config_file" ] && [ -n "$(tail -c 1 "$config_file")" ]; then diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/oval/shared.xml b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/oval/shared.xml deleted file mode 100644 index b630b5740450..000000000000 --- a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/oval/shared.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - {{{ oval_metadata("APT does not explicitly allow insecure repositories.", rule_title=rule_title) }}} - - - - - - - - - /etc/apt/apt\.conf(\.d/.*)?$ - ^[\s]*(?i)Acquire::AllowInsecureRepositories(?-i)[\s]+"?(?i)(1|true|yes|with|on)(?-i)"?[\s]*;[\s]*(#.*)?$ - 1 - - diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/rule.yml b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/rule.yml index 60809b0b2ed5..cf0065dcd87d 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/rule.yml +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/rule.yml @@ -3,7 +3,8 @@ documentation_complete: true title: 'Disable APT AllowInsecureRepositories' description: |- - Configure APT with Acquire::AllowInsecureRepositories "0";. + Configure the effective APT setting with + Acquire::AllowInsecureRepositories "0";. rationale: |- Insecure repositories do not provide authenticated package metadata. diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/sce/shared.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/sce/shared.sh new file mode 100644 index 000000000000..e8c2df4f5cb8 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/sce/shared.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# platform = multi_platform_ubuntu +# check-import = stdout + +explicit=false +for config_file in /etc/apt/apt.conf /etc/apt/apt.conf.d/*; do + [[ -f "$config_file" ]] || continue + [[ "$config_file" == /etc/apt/apt.conf || ${config_file##*/} =~ ^[A-Za-z0-9_-]+$ ]] || continue + grep -Piq '^[\h]*(Acquire::)?AllowInsecureRepositories\h+' "$config_file" && explicit=true +done + +if [[ "$explicit" == true ]] && apt-config dump 2>/dev/null | grep -Piq '^Acquire::AllowInsecureRepositories\s+"?(0|false|no|without|off)"?;$'; then + exit "$XCCDF_RESULT_PASS" +fi + +echo 'Acquire::AllowInsecureRepositories is not explicitly configured with a disabled value.' +exit "$XCCDF_RESULT_FAIL" diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/commented.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/commented_only.fail.sh similarity index 68% rename from linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/commented.pass.sh rename to linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/commented_only.fail.sh index befa67679756..6e1715d1b419 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/commented.pass.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/commented_only.fail.sh @@ -3,6 +3,5 @@ mkdir -p /etc/apt/apt.conf.d touch /etc/apt/apt.conf -find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true - +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*(Acquire::)?AllowInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true echo '# Acquire::AllowInsecureRepositories "1";' >> /etc/apt/apt.conf diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/missing.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/missing.fail.sh new file mode 100644 index 000000000000..10af695c55c8 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/missing.fail.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*(Acquire::)?AllowInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/missing.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/missing.pass.sh deleted file mode 100644 index c740f6b54351..000000000000 --- a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/missing.pass.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# platform = multi_platform_ubuntu - -mkdir -p /etc/apt/apt.conf.d -touch /etc/apt/apt.conf -find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true - -# The APT default is compliant, so no setting at all must pass. -exit 0 diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/nested_correct_value.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/nested_correct_value.pass.sh new file mode 100644 index 000000000000..7ea9a0c1e48a --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/nested_correct_value.pass.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = Ubuntu 26.04 + +mkdir -p /etc/apt/apt.conf.d +printf '%s\n' 'Acquire {' ' AllowInsecureRepositories "0";' '};' > /etc/apt/apt.conf.d/99-cis-repository-security diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/nested_wrong_value.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/nested_wrong_value.fail.sh new file mode 100644 index 000000000000..fc7c79d4989b --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/nested_wrong_value.fail.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +printf '%s\n' 'Acquire {' ' AllowInsecureRepositories "1";' '};' > /etc/apt/apt.conf.d/70-cac-test diff --git a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh index b88b060c9bed..6eebf5aa27e2 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_insecure_repositories/tests/wrong_value_unquoted_dir.fail.sh @@ -5,5 +5,5 @@ mkdir -p /etc/apt/apt.conf.d touch /etc/apt/apt.conf find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowInsecureRepositories[[:space:]]+/Id' {} + 2>/dev/null || true -# APT option names are case insensitive and values may be unquoted. +# APT accepts case-insensitive option names and unquoted values. echo 'acquire::allowinsecurerepositories 1;' >> /etc/apt/apt.conf.d/70-cac-test diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/bash/shared.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/bash/shared.sh index a1e0d5d63a54..524a53a1c627 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/bash/shared.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/bash/shared.sh @@ -6,14 +6,15 @@ config_file=/etc/apt/apt.conf.d/99-cis-repository-security option='Acquire::AllowWeakRepositories' +option_pattern='(Acquire::)?AllowWeakRepositories' setting='Acquire::AllowWeakRepositories "0";' touch "$config_file" -# Drop the option everywhere it is already set, so a conflicting value in -# another APT configuration file cannot re-enable it. +# Remove existing definitions before writing the required value. Otherwise, +# APT file precedence could leave a conflicting definition in effect. while IFS= read -r -d '' apt_conf_file; do - sed -ri "/^[[:space:]]*${option}[[:space:]]+/Id" "$apt_conf_file" + sed -ri "/^[[:space:]]*${option_pattern}[[:space:]]+/Id" "$apt_conf_file" done < <(find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -print0 2>/dev/null) if [ -s "$config_file" ] && [ -n "$(tail -c 1 "$config_file")" ]; then diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/oval/shared.xml b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/oval/shared.xml deleted file mode 100644 index fc69dd71cb9a..000000000000 --- a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/oval/shared.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - {{{ oval_metadata("APT does not explicitly allow weak repositories.", rule_title=rule_title) }}} - - - - - - - - - /etc/apt/apt\.conf(\.d/.*)?$ - ^[\s]*(?i)Acquire::AllowWeakRepositories(?-i)[\s]+"?(?i)(1|true|yes|with|on)(?-i)"?[\s]*;[\s]*(#.*)?$ - 1 - - diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/rule.yml b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/rule.yml index 3982f8b3048e..1087436a9cf1 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/rule.yml +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/rule.yml @@ -3,7 +3,8 @@ documentation_complete: true title: 'Disable APT AllowWeakRepositories' description: |- - Configure APT with Acquire::AllowWeakRepositories "0";. + Configure the effective APT setting with + Acquire::AllowWeakRepositories "0";. rationale: |- Weak repositories use package metadata authentication that does not meet diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/sce/shared.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/sce/shared.sh new file mode 100644 index 000000000000..45174e7a8fe8 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/sce/shared.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# platform = multi_platform_ubuntu +# check-import = stdout + +explicit=false +for config_file in /etc/apt/apt.conf /etc/apt/apt.conf.d/*; do + [[ -f "$config_file" ]] || continue + [[ "$config_file" == /etc/apt/apt.conf || ${config_file##*/} =~ ^[A-Za-z0-9_-]+$ ]] || continue + grep -Piq '^[\h]*(Acquire::)?AllowWeakRepositories\h+' "$config_file" && explicit=true +done + +if [[ "$explicit" == true ]] && apt-config dump 2>/dev/null | grep -Piq '^Acquire::AllowWeakRepositories\s+"?(0|false|no|without|off)"?;$'; then + exit "$XCCDF_RESULT_PASS" +fi + +echo 'Acquire::AllowWeakRepositories is not explicitly configured with a disabled value.' +exit "$XCCDF_RESULT_FAIL" diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/commented.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/commented_only.fail.sh similarity index 69% rename from linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/commented.pass.sh rename to linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/commented_only.fail.sh index f01aa2363ab1..7b9bdc9061bf 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/commented.pass.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/commented_only.fail.sh @@ -3,6 +3,5 @@ mkdir -p /etc/apt/apt.conf.d touch /etc/apt/apt.conf -find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowWeakRepositories[[:space:]]+/Id' {} + 2>/dev/null || true - +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*(Acquire::)?AllowWeakRepositories[[:space:]]+/Id' {} + 2>/dev/null || true echo '# Acquire::AllowWeakRepositories "1";' >> /etc/apt/apt.conf diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/missing.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/missing.fail.sh new file mode 100644 index 000000000000..4626fe1d1867 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/missing.fail.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*(Acquire::)?AllowWeakRepositories[[:space:]]+/Id' {} + 2>/dev/null || true diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/missing.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/missing.pass.sh deleted file mode 100644 index 53e4284d9304..000000000000 --- a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/missing.pass.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# platform = multi_platform_ubuntu - -mkdir -p /etc/apt/apt.conf.d -touch /etc/apt/apt.conf -find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowWeakRepositories[[:space:]]+/Id' {} + 2>/dev/null || true - -# The APT default is compliant, so no setting at all must pass. -exit 0 diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/nested_correct_value.pass.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/nested_correct_value.pass.sh new file mode 100644 index 000000000000..eb5b45511e7e --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/nested_correct_value.pass.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = Ubuntu 26.04 + +mkdir -p /etc/apt/apt.conf.d +printf '%s\n' 'Acquire {' ' AllowWeakRepositories "0";' '};' > /etc/apt/apt.conf.d/99-cis-repository-security diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/nested_wrong_value.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/nested_wrong_value.fail.sh new file mode 100644 index 000000000000..d11edbf0e15b --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/nested_wrong_value.fail.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +printf '%s\n' 'Acquire {' ' AllowWeakRepositories "1";' '};' > /etc/apt/apt.conf.d/70-cac-test diff --git a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/wrong_value_unquoted_dir.fail.sh b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/wrong_value_unquoted_dir.fail.sh index fc5cbb7cb27c..d3e7cc676955 100644 --- a/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/wrong_value_unquoted_dir.fail.sh +++ b/linux_os/guide/services/apt/apt_configure_allow_weak_repositories/tests/wrong_value_unquoted_dir.fail.sh @@ -5,5 +5,5 @@ mkdir -p /etc/apt/apt.conf.d touch /etc/apt/apt.conf find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::AllowWeakRepositories[[:space:]]+/Id' {} + 2>/dev/null || true -# APT option names are case insensitive and values may be unquoted. +# APT accepts case-insensitive option names and unquoted values. echo 'acquire::allowweakrepositories 1;' >> /etc/apt/apt.conf.d/70-cac-test diff --git a/linux_os/guide/services/apt/apt_configure_check_date/bash/shared.sh b/linux_os/guide/services/apt/apt_configure_check_date/bash/shared.sh index d79e9a60d1f8..126f6bda5312 100644 --- a/linux_os/guide/services/apt/apt_configure_check_date/bash/shared.sh +++ b/linux_os/guide/services/apt/apt_configure_check_date/bash/shared.sh @@ -6,14 +6,15 @@ config_file=/etc/apt/apt.conf.d/99-cis-repository-security option='Acquire::Check-Date' +option_pattern='(Acquire::)?Check-Date' setting='Acquire::Check-Date "true";' touch "$config_file" -# Drop the option everywhere it is already set, so a conflicting value in -# another APT configuration file cannot re-enable it. +# Remove existing definitions before writing the required value. Otherwise, +# APT file precedence could leave a conflicting definition in effect. while IFS= read -r -d '' apt_conf_file; do - sed -ri "/^[[:space:]]*${option}[[:space:]]+/Id" "$apt_conf_file" + sed -ri "/^[[:space:]]*${option_pattern}[[:space:]]+/Id" "$apt_conf_file" done < <(find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -print0 2>/dev/null) if [ -s "$config_file" ] && [ -n "$(tail -c 1 "$config_file")" ]; then diff --git a/linux_os/guide/services/apt/apt_configure_check_date/oval/shared.xml b/linux_os/guide/services/apt/apt_configure_check_date/oval/shared.xml deleted file mode 100644 index b746a2278740..000000000000 --- a/linux_os/guide/services/apt/apt_configure_check_date/oval/shared.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - {{{ oval_metadata("APT date checking is not explicitly disabled.", rule_title=rule_title) }}} - - - - - - - - - /etc/apt/apt\.conf(\.d/.*)?$ - ^[\s]*(?i)Acquire::Check-Date(?-i)[\s]+"?(?i)(0|false|no|without|off)(?-i)"?[\s]*;[\s]*(#.*)?$ - 1 - - diff --git a/linux_os/guide/services/apt/apt_configure_check_date/rule.yml b/linux_os/guide/services/apt/apt_configure_check_date/rule.yml index ddcaebbee12a..ee50a796d917 100644 --- a/linux_os/guide/services/apt/apt_configure_check_date/rule.yml +++ b/linux_os/guide/services/apt/apt_configure_check_date/rule.yml @@ -3,7 +3,8 @@ documentation_complete: true title: 'Enable APT Check-Date' description: |- - Configure APT with Acquire::Check-Date "true";. + Configure the effective APT setting with + Acquire::Check-Date "true";. rationale: |- APT must validate repository metadata dates to reject stale or not-yet-valid diff --git a/linux_os/guide/services/apt/apt_configure_check_date/sce/shared.sh b/linux_os/guide/services/apt/apt_configure_check_date/sce/shared.sh new file mode 100644 index 000000000000..b0ac05efe5fd --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_check_date/sce/shared.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# platform = multi_platform_ubuntu +# check-import = stdout + +explicit=false +for config_file in /etc/apt/apt.conf /etc/apt/apt.conf.d/*; do + [[ -f "$config_file" ]] || continue + [[ "$config_file" == /etc/apt/apt.conf || ${config_file##*/} =~ ^[A-Za-z0-9_-]+$ ]] || continue + grep -Piq '^[\h]*(Acquire::)?Check-Date\h+' "$config_file" && explicit=true +done + +if [[ "$explicit" == true ]] && apt-config dump 2>/dev/null | grep -Piq '^Acquire::Check-Date\s+"?(1|true|yes|with|on)"?;$'; then + exit "$XCCDF_RESULT_PASS" +fi + +echo 'Acquire::Check-Date is not explicitly configured with an enabled value.' +exit "$XCCDF_RESULT_FAIL" diff --git a/linux_os/guide/services/apt/apt_configure_check_date/tests/commented.pass.sh b/linux_os/guide/services/apt/apt_configure_check_date/tests/commented_only.fail.sh similarity index 70% rename from linux_os/guide/services/apt/apt_configure_check_date/tests/commented.pass.sh rename to linux_os/guide/services/apt/apt_configure_check_date/tests/commented_only.fail.sh index 1b9241252b27..a015133408de 100644 --- a/linux_os/guide/services/apt/apt_configure_check_date/tests/commented.pass.sh +++ b/linux_os/guide/services/apt/apt_configure_check_date/tests/commented_only.fail.sh @@ -3,6 +3,5 @@ mkdir -p /etc/apt/apt.conf.d touch /etc/apt/apt.conf -find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::Check-Date[[:space:]]+/Id' {} + 2>/dev/null || true - +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*(Acquire::)?Check-Date[[:space:]]+/Id' {} + 2>/dev/null || true echo '# Acquire::Check-Date "false";' >> /etc/apt/apt.conf diff --git a/linux_os/guide/services/apt/apt_configure_check_date/tests/missing.fail.sh b/linux_os/guide/services/apt/apt_configure_check_date/tests/missing.fail.sh new file mode 100644 index 000000000000..ad6a4cd63b03 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_check_date/tests/missing.fail.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +touch /etc/apt/apt.conf +find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*(Acquire::)?Check-Date[[:space:]]+/Id' {} + 2>/dev/null || true diff --git a/linux_os/guide/services/apt/apt_configure_check_date/tests/nested_correct_value.pass.sh b/linux_os/guide/services/apt/apt_configure_check_date/tests/nested_correct_value.pass.sh new file mode 100644 index 000000000000..146537538fda --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_check_date/tests/nested_correct_value.pass.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = Ubuntu 26.04 + +mkdir -p /etc/apt/apt.conf.d +printf '%s\n' 'Acquire {' ' Check-Date "true";' '};' > /etc/apt/apt.conf.d/99-cis-repository-security diff --git a/linux_os/guide/services/apt/apt_configure_check_date/tests/nested_wrong_value.fail.sh b/linux_os/guide/services/apt/apt_configure_check_date/tests/nested_wrong_value.fail.sh new file mode 100644 index 000000000000..e24ca1819772 --- /dev/null +++ b/linux_os/guide/services/apt/apt_configure_check_date/tests/nested_wrong_value.fail.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +mkdir -p /etc/apt/apt.conf.d +printf '%s\n' 'Acquire {' ' Check-Date "false";' '};' > /etc/apt/apt.conf.d/70-cac-test diff --git a/linux_os/guide/services/apt/apt_configure_check_date/tests/wrong_value_unquoted_dir.fail.sh b/linux_os/guide/services/apt/apt_configure_check_date/tests/wrong_value_unquoted_dir.fail.sh index 18786c1daf50..8a56e23ca6a8 100644 --- a/linux_os/guide/services/apt/apt_configure_check_date/tests/wrong_value_unquoted_dir.fail.sh +++ b/linux_os/guide/services/apt/apt_configure_check_date/tests/wrong_value_unquoted_dir.fail.sh @@ -5,5 +5,5 @@ mkdir -p /etc/apt/apt.conf.d touch /etc/apt/apt.conf find /etc/apt/apt.conf /etc/apt/apt.conf.d -maxdepth 1 -type f -exec sed -ri '/^[[:space:]]*Acquire::Check-Date[[:space:]]+/Id' {} + 2>/dev/null || true -# APT option names are case insensitive and values may be unquoted. +# APT accepts case-insensitive option names and unquoted values. echo 'acquire::check-date false;' >> /etc/apt/apt.conf.d/70-cac-test diff --git a/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_deb822_second_uri.fail.sh b/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_deb822_second_uri.fail.sh index 5b02008dbb51..d310217a9d93 100644 --- a/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_deb822_second_uri.fail.sh +++ b/linux_os/guide/services/apt/apt_sources_list_d_https/tests/http_deb822_second_uri.fail.sh @@ -2,7 +2,7 @@ # platform = multi_platform_ubuntu find /etc/apt/sources.list.d -maxdepth 1 -type f \( -name '*.list' -o -name '*.sources' \) -exec sed -ri 's#http://#https://#g' {} + 2>/dev/null || true -# A URIs line may carry several URIs; an http:// one after an https:// one still counts. +# Check every URL on a URIs line, including HTTP URLs after an HTTPS URL. cat > /etc/apt/sources.list.d/cac-test.sources <<'EOF' Types: deb URIs: https://archive.ubuntu.com/ubuntu http://security.ubuntu.com/ubuntu diff --git a/linux_os/guide/services/apt/apt_sources_list_https/tests/absent_sources_list.pass.sh b/linux_os/guide/services/apt/apt_sources_list_https/tests/absent_sources_list.pass.sh index f056d78ccd25..5bbe4348362a 100644 --- a/linux_os/guide/services/apt/apt_sources_list_https/tests/absent_sources_list.pass.sh +++ b/linux_os/guide/services/apt/apt_sources_list_https/tests/absent_sources_list.pass.sh @@ -1,5 +1,5 @@ #!/bin/bash # platform = multi_platform_ubuntu -# Ubuntu 26.04 uses deb822 and ships no /etc/apt/sources.list at all. +# Ubuntu 26.04 uses deb822 by default and may omit /etc/apt/sources.list. rm -f /etc/apt/sources.list diff --git a/linux_os/guide/services/apt/apt_sources_list_https/tests/http_entry_with_options.fail.sh b/linux_os/guide/services/apt/apt_sources_list_https/tests/http_entry_with_options.fail.sh index 2341c0b19205..81ddfcf29d37 100644 --- a/linux_os/guide/services/apt/apt_sources_list_https/tests/http_entry_with_options.fail.sh +++ b/linux_os/guide/services/apt/apt_sources_list_https/tests/http_entry_with_options.fail.sh @@ -1,7 +1,7 @@ #!/bin/bash # platform = multi_platform_ubuntu -# An options block between deb and the URI must not hide the http:// entry. +# Parse the URI after an optional deb options block. cat > /etc/apt/sources.list <<'EOF' deb [signed-by=/usr/share/keyrings/ubuntu-archive-keyring.gpg] http://archive.ubuntu.com/ubuntu resolute main EOF From 594096a86d098c6ae5226ae818bf65a4ccc21799 Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 15:30:51 +1200 Subject: [PATCH 07/18] Add Ubuntu 26.04 sshd effective-value checks --- components/openssh.yml | 3 +++ .../sshd_disable_empty_passwords/rule.yml | 3 --- .../tests/line_not_there.pass.sh | 17 ------------- .../tests/test_config.yml | 2 -- .../bash/shared.sh | 14 +++++++++++ .../rule.yml | 21 ++++++++++++++++ .../sce/shared.sh | 10 ++++++++ .../tests/explicit_no.pass.sh | 6 +++++ .../tests/explicit_yes.fail.sh | 6 +++++ .../tests/missing_uses_default.pass.sh | 5 ++++ .../sshd_set_keepalive/oval/ubuntu2604.xml | 21 ---------------- .../bash/shared.sh | 15 ++++++++++++ .../sshd_set_keepalive_positive/rule.yml | 24 +++++++++++++++++++ .../sshd_set_keepalive_positive/sce/shared.sh | 11 +++++++++ .../tests/missing_default.pass.sh | 5 ++++ .../tests/positive.pass.sh | 6 +++++ .../tests/zero.fail.sh | 6 +++++ .../sshd_use_strong_kex/oval/ubuntu2604.xml | 20 ---------------- .../bash/shared.sh | 15 ++++++++++++ .../sshd_use_strong_kex_ubuntu2604/rule.yml | 23 ++++++++++++++++++ .../sce/shared.sh | 11 +++++++++ .../tests/default_algorithms.pass.sh | 5 ++++ .../tests/subtractive_denylist.pass.sh | 6 +++++ .../tests/weak_algorithm.fail.sh | 6 +++++ .../guide/services/ssh/sshd_strong_kex.var | 1 - 25 files changed, 198 insertions(+), 64 deletions(-) delete mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/line_not_there.pass.sh delete mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/test_config.yml create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/bash/shared.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/rule.yml create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/sce/shared.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/tests/explicit_no.pass.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/tests/explicit_yes.fail.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/tests/missing_uses_default.pass.sh delete mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive/oval/ubuntu2604.xml create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/bash/shared.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/rule.yml create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/sce/shared.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/tests/missing_default.pass.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/tests/positive.pass.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/tests/zero.fail.sh delete mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex/oval/ubuntu2604.xml create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/bash/shared.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/rule.yml create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/sce/shared.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/tests/default_algorithms.pass.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/tests/subtractive_denylist.pass.sh create mode 100644 linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/tests/weak_algorithm.fail.sh diff --git a/components/openssh.yml b/components/openssh.yml index b8e08696d8b5..96d33debd502 100644 --- a/components/openssh.yml +++ b/components/openssh.yml @@ -51,6 +51,7 @@ rules: - sshd_allow_only_protocol2 - sshd_disable_compression - sshd_disable_empty_passwords +- sshd_disable_empty_passwords_default - sshd_disable_forwarding - sshd_disable_gssapi_auth - sshd_disable_kerb_auth @@ -77,6 +78,7 @@ rules: - sshd_set_idle_timeout - sshd_set_keepalive - sshd_set_keepalive_0 +- sshd_set_keepalive_positive - sshd_set_login_grace_time - sshd_set_loglevel_info - sshd_set_loglevel_verbose @@ -92,6 +94,7 @@ rules: - sshd_use_priv_separation - sshd_use_strong_ciphers - sshd_use_strong_kex +- sshd_use_strong_kex_ubuntu2604 - sshd_use_strong_macs - sshd_use_strong_rng - sshd_x11_use_localhost diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/rule.yml b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/rule.yml index 9ee8162a36bf..608f5e6c169b 100644 --- a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/rule.yml +++ b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/rule.yml @@ -67,6 +67,3 @@ template: value: 'no' datatype: string is_default_value: 'true' -{{% if product in ["ubuntu2604"] %}} - missing_parameter_pass: 'true' -{{% endif %}} diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/line_not_there.pass.sh b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/line_not_there.pass.sh deleted file mode 100644 index aa7ad21a623e..000000000000 --- a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/line_not_there.pass.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# platform = multi_platform_ubuntu - -SSHD_PARAM={{{ PARAMETER }}} - -mkdir -p "{{{ sshd_config_dir }}}" -touch "{{{ sshd_config_dir }}}/nothing" -declare -a SSHD_PATHS=({{{ sshd_main_config_file }}} {{{ sshd_config_dir }}}/*) - -{{% if product in ['sle16', 'slmicro6'] %}} -touch "{{{ sshd_main_config_file }}}" -{{% endif %}} - -if grep -q "^\s*${SSHD_PARAM}" "${SSHD_PATHS[@]}" ; then - sed -i "/^\s*${SSHD_PARAM}.*/Id" "${SSHD_PATHS[@]}" -fi diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/test_config.yml b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/test_config.yml deleted file mode 100644 index 998c331c5661..000000000000 --- a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords/tests/test_config.yml +++ /dev/null @@ -1,2 +0,0 @@ -deny_templated_scenarios: - - line_not_there.fail.sh diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/bash/shared.sh b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/bash/shared.sh new file mode 100644 index 000000000000..681aa6decf04 --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/bash/shared.sh @@ -0,0 +1,14 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = restrict +# complexity = low +# disruption = low + +{{{ + bash_sshd_remediation( + parameter="PermitEmptyPasswords", + value="no", + config_is_distributed=sshd_distributed_config, + rule_id=rule_id + ) +}}} diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/rule.yml b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/rule.yml new file mode 100644 index 000000000000..cecda821bbd8 --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/rule.yml @@ -0,0 +1,21 @@ +documentation_complete: true + +title: 'Disable SSH Access Through Empty Passwords, Including the Secure Default' + +description: |- + The effective SSH daemon configuration must set + PermitEmptyPasswords to no. An omitted directive is + compliant because the OpenSSH default is no. + +rationale: |- + Accounts with empty passwords must not be usable for remote SSH access. + +severity: high + +platform: package[openssh-server] + +ocil_clause: 'the effective PermitEmptyPasswords value is not no' + +ocil: |- + Run sshd -T | grep permitemptypasswords and verify the result is + permitemptypasswords no. diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/sce/shared.sh b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/sce/shared.sh new file mode 100644 index 000000000000..f4007cd24ab3 --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/sce/shared.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# check-import = stdout + +if /usr/sbin/sshd -T 2>/dev/null | grep -Piq '^permitemptypasswords\s+no$'; then + exit "$XCCDF_RESULT_PASS" +fi + +echo 'The effective PermitEmptyPasswords value is not no.' +exit "$XCCDF_RESULT_FAIL" diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/tests/explicit_no.pass.sh b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/tests/explicit_no.pass.sh new file mode 100644 index 000000000000..c4e1490999f4 --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/tests/explicit_no.pass.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# packages = openssh-server + +mkdir -p /etc/ssh/sshd_config.d +echo 'PermitEmptyPasswords no' > /etc/ssh/sshd_config.d/00-cis-test.conf diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/tests/explicit_yes.fail.sh b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/tests/explicit_yes.fail.sh new file mode 100644 index 000000000000..d76e0a14fa8a --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/tests/explicit_yes.fail.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# packages = openssh-server + +mkdir -p /etc/ssh/sshd_config.d +echo 'PermitEmptyPasswords yes' > /etc/ssh/sshd_config.d/00-cis-test.conf diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/tests/missing_uses_default.pass.sh b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/tests/missing_uses_default.pass.sh new file mode 100644 index 000000000000..2f13951e9a9c --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_disable_empty_passwords_default/tests/missing_uses_default.pass.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# packages = openssh-server + +sed -ri '/^[[:space:]]*PermitEmptyPasswords[[:space:]]+/Id' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null || true diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive/oval/ubuntu2604.xml b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive/oval/ubuntu2604.xml deleted file mode 100644 index 52df8a1259aa..000000000000 --- a/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive/oval/ubuntu2604.xml +++ /dev/null @@ -1,21 +0,0 @@ -{{%- set sshd_main_config = sshd_main_config_file -%}} - - - {{{ oval_metadata("ClientAliveCountMax is greater than zero, including the compliant OpenSSH default of 3.", rule_title=rule_title) }}} - - - - - - - - - - {{{ sshd_main_config }}}(\.d/.*\.conf)?$ - ^[\s]*(?i)ClientAliveCountMax(?-i)[\s]+0[\s]*(#.*)?$ - 1 - - diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/bash/shared.sh b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/bash/shared.sh new file mode 100644 index 000000000000..2a67ad4824c4 --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/bash/shared.sh @@ -0,0 +1,15 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = configure +# complexity = low +# disruption = low + +{{{ bash_instantiate_variables("var_sshd_set_keepalive") }}} +{{{ + bash_sshd_remediation( + parameter="ClientAliveCountMax", + value="$var_sshd_set_keepalive", + config_is_distributed=sshd_distributed_config, + rule_id=rule_id + ) +}}} diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/rule.yml b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/rule.yml new file mode 100644 index 000000000000..583a65c1092b --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/rule.yml @@ -0,0 +1,24 @@ +documentation_complete: true + +title: 'Set SSH Client Alive Count Max Greater Than Zero' + +description: |- + The effective ClientAliveCountMax value must be greater than zero. + An omitted directive is compliant because the OpenSSH default is 3. + +rationale: |- + A positive count allows the SSH daemon to terminate an unresponsive + connection after the configured client-alive interval. + +severity: medium + +platform: package[openssh-server] + +requires: + - sshd_set_idle_timeout + +ocil_clause: 'the effective ClientAliveCountMax value is zero' + +ocil: |- + Run sshd -T | grep clientalivecountmax and verify the value is + greater than zero. diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/sce/shared.sh b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/sce/shared.sh new file mode 100644 index 000000000000..b703fde3e628 --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/sce/shared.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# check-import = stdout + +value=$(/usr/sbin/sshd -T 2>/dev/null | awk '$1 == "clientalivecountmax" { print $2; exit }') +if [[ "$value" =~ ^[0-9]+$ ]] && (( value > 0 )); then + exit "$XCCDF_RESULT_PASS" +fi + +echo "The effective ClientAliveCountMax value is '${value:-unavailable}', not greater than zero." +exit "$XCCDF_RESULT_FAIL" diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/tests/missing_default.pass.sh b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/tests/missing_default.pass.sh new file mode 100644 index 000000000000..a2ed2770f5cc --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/tests/missing_default.pass.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# packages = openssh-server + +sed -ri '/^[[:space:]]*ClientAliveCountMax[[:space:]]+/Id' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null || true diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/tests/positive.pass.sh b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/tests/positive.pass.sh new file mode 100644 index 000000000000..1b24772ef50c --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/tests/positive.pass.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# packages = openssh-server + +mkdir -p /etc/ssh/sshd_config.d +echo 'ClientAliveCountMax 1' > /etc/ssh/sshd_config.d/00-cis-test.conf diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/tests/zero.fail.sh b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/tests/zero.fail.sh new file mode 100644 index 000000000000..c8e743e11d12 --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_set_keepalive_positive/tests/zero.fail.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# packages = openssh-server + +mkdir -p /etc/ssh/sshd_config.d +echo 'ClientAliveCountMax 0' > /etc/ssh/sshd_config.d/00-cis-test.conf diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex/oval/ubuntu2604.xml b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex/oval/ubuntu2604.xml deleted file mode 100644 index 4d656f9c723a..000000000000 --- a/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex/oval/ubuntu2604.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - {{{ oval_metadata("SSH key exchange excludes the algorithms prohibited by CIS Ubuntu 26.04.", rule_title=rule_title) }}} - - - - - - - - - - /etc/ssh/sshd_config(\.d/.*\.conf)?$ - ^[\s]*(?i)KexAlgorithms(?-i)[\s]+(?!-)[^#\n]*(diffie-hellman-group1-sha1|diffie-hellman-group14-sha1|diffie-hellman-group-exchange-sha1)(,|[\s#]|$).*$ - 1 - - diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/bash/shared.sh b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/bash/shared.sh new file mode 100644 index 000000000000..5d7d51dc95cf --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/bash/shared.sh @@ -0,0 +1,15 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = restrict +# complexity = low +# disruption = low + +weak_kex='-diffie-hellman-group1-sha1,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1' +{{{ + bash_sshd_remediation( + parameter="KexAlgorithms", + value="$weak_kex", + config_is_distributed=sshd_distributed_config, + rule_id=rule_id + ) +}}} diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/rule.yml b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/rule.yml new file mode 100644 index 000000000000..f5da5f7e8db0 --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/rule.yml @@ -0,0 +1,23 @@ +documentation_complete: true + +title: 'Disable SSH Key Exchange Algorithms Prohibited by CIS Ubuntu 26.04' + +description: |- + The effective SSH key-exchange list must not contain + diffie-hellman-group1-sha1, + diffie-hellman-group14-sha1, or + diffie-hellman-group-exchange-sha1. + +rationale: |- + SHA-1 key-exchange algorithms do not provide adequate protection against + modern cryptographic attacks. + +severity: medium + +platform: package[openssh-server] + +ocil_clause: 'the effective SSH key-exchange list contains a prohibited algorithm' + +ocil: |- + Run sshd -T | grep kexalgorithms. The effective list must not + contain any of the three prohibited SHA-1 algorithms. diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/sce/shared.sh b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/sce/shared.sh new file mode 100644 index 000000000000..2170bd75c611 --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/sce/shared.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# check-import = stdout + +kex=$(/usr/sbin/sshd -T 2>/dev/null | awk '$1 == "kexalgorithms" { print $2; exit }') +if [[ -n "$kex" ]] && ! grep -Piq '(^|,)(diffie-hellman-group1-sha1|diffie-hellman-group14-sha1|diffie-hellman-group-exchange-sha1)(,|$)' <<< "$kex"; then + exit "$XCCDF_RESULT_PASS" +fi + +echo 'The effective KexAlgorithms list contains a CIS-prohibited SHA-1 algorithm or could not be read.' +exit "$XCCDF_RESULT_FAIL" diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/tests/default_algorithms.pass.sh b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/tests/default_algorithms.pass.sh new file mode 100644 index 000000000000..fe71a2b79b86 --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/tests/default_algorithms.pass.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# packages = openssh-server + +sed -ri '/^[[:space:]]*KexAlgorithms[[:space:]]+/Id' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf 2>/dev/null || true diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/tests/subtractive_denylist.pass.sh b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/tests/subtractive_denylist.pass.sh new file mode 100644 index 000000000000..c6242b577b14 --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/tests/subtractive_denylist.pass.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# packages = openssh-server + +mkdir -p /etc/ssh/sshd_config.d +echo 'KexAlgorithms -diffie-hellman-group1-sha1,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha1' > /etc/ssh/sshd_config.d/00-cis-test.conf diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/tests/weak_algorithm.fail.sh b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/tests/weak_algorithm.fail.sh new file mode 100644 index 000000000000..861317d5e5fc --- /dev/null +++ b/linux_os/guide/services/ssh/ssh_server/sshd_use_strong_kex_ubuntu2604/tests/weak_algorithm.fail.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# packages = openssh-server + +mkdir -p /etc/ssh/sshd_config.d +echo 'KexAlgorithms +diffie-hellman-group14-sha1' > /etc/ssh/sshd_config.d/00-cis-test.conf diff --git a/linux_os/guide/services/ssh/sshd_strong_kex.var b/linux_os/guide/services/ssh/sshd_strong_kex.var index bb6b41d4babe..38053e889b09 100644 --- a/linux_os/guide/services/ssh/sshd_strong_kex.var +++ b/linux_os/guide/services/ssh/sshd_strong_kex.var @@ -20,7 +20,6 @@ options: cis_sle15: 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 cis_ubuntu2204: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256 cis_ubuntu2404: sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256 - cis_ubuntu2604: mlkem768x25519-sha256,sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256 std_openeuler: curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 std_kylinsecserver6: curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 cis_debian12: sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256 From 1987361095a3259b0d59e92ce944799a199378d4 Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 15:31:07 +1200 Subject: [PATCH 08/18] Fix PAM MOTD and home dot-directory checks --- .../file_permissions_pam_motd/bash/shared.sh | 13 ++++ .../file_permissions_pam_motd/oval/shared.xml | 39 ------------ .../file_permissions_pam_motd/rule.yml | 3 + .../file_permissions_pam_motd/sce/shared.sh | 31 ++++++++++ .../tests/correct_access.pass.sh | 2 +- .../other_service_world_writable.fail.sh | 10 +++ .../tests/quoted_path.pass.sh | 10 +++ .../tests/world_writable.fail.sh | 3 +- .../pam_motd_configured/bash/shared.sh | 26 ++++++++ .../pam_motd_configured/oval/shared.xml | 51 --------------- .../pam_motd_configured/sce/shared.sh | 44 +++++++++++++ .../tests/explicit_safe_motd.pass.sh | 2 +- .../tests/motd_discloses_os.fail.sh | 3 +- .../tests/no_explicit_path.fail.sh | 5 +- .../tests/quoted_path.pass.sh | 8 +++ .../bash/shared.sh | 16 +++++ .../oval/shared.xml | 39 ------------ .../rule.yml | 12 ++-- .../sce/shared.sh | 20 ++++++ .../tests/expected_owner.pass.sh | 1 + .../tests/swapped_group_owners.fail.sh | 9 +++ .../tests/unexpected_owner_system_id.fail.sh | 2 +- .../warning_swapped_group_owners.pass.sh | 11 ---- .../bash/shared.sh | 16 +++++ .../oval/shared.xml | 39 ------------ .../accounts_user_dot_dirs_ownership/rule.yml | 12 ++-- .../sce/shared.sh | 20 ++++++ .../tests/expected_owner.pass.sh | 1 + .../tests/swapped_owners.fail.sh | 9 +++ .../tests/unexpected_owner_system_id.fail.sh | 2 +- .../tests/warning_swapped_owners.pass.sh | 11 ---- .../bash/shared.sh | 20 ++++++ .../oval/shared.xml | 62 ------------------- .../sce/shared.sh | 22 +++++++ .../tests/group_writable_dot_dir.fail.sh | 2 +- .../tests/restrictive_modes.pass.sh | 1 + .../tests/world_readable_ssh_dir.fail.sh | 2 +- 37 files changed, 302 insertions(+), 277 deletions(-) create mode 100644 linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/bash/shared.sh delete mode 100644 linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/oval/shared.xml create mode 100644 linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/sce/shared.sh create mode 100644 linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/other_service_world_writable.fail.sh create mode 100644 linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/quoted_path.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/bash/shared.sh delete mode 100644 linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/oval/shared.xml create mode 100644 linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/sce/shared.sh create mode 100644 linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/quoted_path.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/bash/shared.sh delete mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/oval/shared.xml create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/sce/shared.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/swapped_group_owners.fail.sh delete mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/warning_swapped_group_owners.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/bash/shared.sh delete mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/oval/shared.xml create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/sce/shared.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/swapped_owners.fail.sh delete mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/warning_swapped_owners.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/bash/shared.sh delete mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/oval/shared.xml create mode 100644 linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/sce/shared.sh diff --git a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/bash/shared.sh b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/bash/shared.sh new file mode 100644 index 000000000000..297ea25fbb4d --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/bash/shared.sh @@ -0,0 +1,13 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = restrict +# complexity = low +# disruption = low + +while IFS= read -r motd_path; do + motd_path=${motd_path#\"}; motd_path=${motd_path%\"} + motd_path=${motd_path#\'}; motd_path=${motd_path%\'} + [[ -e "$motd_path" ]] || continue + chown root:root "$motd_path" + chmod u-x,go-wx "$motd_path" +done < <(grep -hPoi '^\h*session\h+(required|optional)\h+pam_motd\.so\b.*\bmotd=\K("[^"]+"|'"'"'[^'"'"']+'"'"'|\S+)' /etc/pam.d/* 2>/dev/null | sort -u) diff --git a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/oval/shared.xml b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/oval/shared.xml deleted file mode 100644 index 0dc3277cf3f6..000000000000 --- a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/oval/shared.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - {{{ oval_metadata("pam_motd message files have secure ownership and permissions.", rule_title=rule_title) }}} - - - - - - - /etc/pam.d - ^(sshd|login|su|gdm-password)$ - ^[\s]*session[\s]+[^#\n]*pam_motd\.so[^#\n]*[\s]motd=([^\s#]+).*$ - 1 - - - - - - - - - - - - - - 0 - 0 - false - false - false - false - false - - diff --git a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/rule.yml b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/rule.yml index b3f8030d4cbd..03f8bdd5bc83 100644 --- a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/rule.yml +++ b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/rule.yml @@ -14,6 +14,9 @@ severity: medium platform: package[pam] +requires: + - pam_motd_configured + ocil_clause: 'a referenced pam_motd file is not root-owned or is more permissive than 0644' ocil: |- diff --git a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/sce/shared.sh b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/sce/shared.sh new file mode 100644 index 000000000000..bba49203467e --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/sce/shared.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# check-import = stdout + +result=$XCCDF_RESULT_PASS +found_path=false + +while IFS= read -r motd_path; do + motd_path=${motd_path#\"}; motd_path=${motd_path%\"} + motd_path=${motd_path#\'}; motd_path=${motd_path%\'} + found_path=true + + if [[ ! -e "$motd_path" ]]; then + echo "$motd_path does not exist." + result=$XCCDF_RESULT_FAIL + continue + fi + + read -r mode uid gid < <(stat -Lc '%a %u %g' "$motd_path") + if (( 8#$mode & 0133 )) || [[ "$uid" != 0 || "$gid" != 0 ]]; then + echo "$motd_path has mode $mode and owner $uid:$gid; expected root:root and 0644 or more restrictive." + result=$XCCDF_RESULT_FAIL + fi +done < <(grep -hPoi '^\h*session\h+(required|optional)\h+pam_motd\.so\b.*\bmotd=\K("[^"]+"|'"'"'[^'"'"']+'"'"'|\S+)' /etc/pam.d/* 2>/dev/null | sort -u) + +if [[ "$found_path" != true ]]; then + echo 'No explicit pam_motd message path was found in /etc/pam.d.' + result=$XCCDF_RESULT_FAIL +fi + +exit "$result" diff --git a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/correct_access.pass.sh b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/correct_access.pass.sh index 21d8a166e285..12e4df3369fb 100644 --- a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/correct_access.pass.sh +++ b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/correct_access.pass.sh @@ -1,7 +1,7 @@ #!/bin/bash # platform = multi_platform_ubuntu -# Remove every pam_motd entry the check looks at, so each scenario starts clean. +# Remove pam_motd entries from every PAM file checked by this rule. for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/su /etc/pam.d/gdm-password; do [ -f "$f" ] && sed -ri '/pam_motd\.so/d' "$f" done diff --git a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/other_service_world_writable.fail.sh b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/other_service_world_writable.fail.sh new file mode 100644 index 000000000000..94a84e19f300 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/other_service_world_writable.fail.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# platform = Ubuntu 26.04 + +for f in /etc/pam.d/*; do + [[ -f "$f" ]] && sed -ri '/pam_motd\.so/d' "$f" +done +printf 'Authorized use only.\n' > /etc/motd.cac +chown root:root /etc/motd.cac +chmod 0666 /etc/motd.cac +echo 'session optional pam_motd.so motd=/etc/motd.cac' > /etc/pam.d/cac-other-service diff --git a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/quoted_path.pass.sh b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/quoted_path.pass.sh new file mode 100644 index 000000000000..879978fb98fe --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/quoted_path.pass.sh @@ -0,0 +1,10 @@ +#!/bin/bash +# platform = Ubuntu 26.04 + +for f in /etc/pam.d/*; do + [[ -f "$f" ]] && sed -ri '/pam_motd\.so/d' "$f" +done +printf 'Authorized use only.\n' > /etc/motd.cac +chown root:root /etc/motd.cac +chmod 0644 /etc/motd.cac +echo 'session optional pam_motd.so motd="/etc/motd.cac"' >> /etc/pam.d/sshd diff --git a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/world_writable.fail.sh b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/world_writable.fail.sh index 3c938493466f..f07baede1f68 100644 --- a/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/world_writable.fail.sh +++ b/linux_os/guide/system/accounts/accounts-banners/file_permissions_pam_motd/tests/world_writable.fail.sh @@ -1,8 +1,7 @@ #!/bin/bash # platform = multi_platform_ubuntu -# remediation = none -# Remove every pam_motd entry the check looks at, so each scenario starts clean. +# Remove pam_motd entries from every PAM file checked by this rule. for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/su /etc/pam.d/gdm-password; do [ -f "$f" ] && sed -ri '/pam_motd\.so/d' "$f" done diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/bash/shared.sh b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/bash/shared.sh new file mode 100644 index 000000000000..2dd68aafb014 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/bash/shared.sh @@ -0,0 +1,26 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = configure +# complexity = medium +# disruption = medium + +os_id=$(awk -F= '$1 == "ID" { gsub(/^"|"$/, "", $2); print $2; exit }' /etc/os-release 2>/dev/null) +touch /etc/motd +chown root:root /etc/motd +chmod u-x,go-wx /etc/motd + +for service in sshd login su gdm-password; do + pam_file="/etc/pam.d/$service" + [[ -f "$pam_file" ]] || continue + sed -ri '/^[[:space:]]*session[[:space:]]+(required|optional)[[:space:]]+pam_motd\.so\b/I {/\bmotd=/! s#[[:space:]]*$# motd=/etc/motd#}' "$pam_file" +done + +while IFS= read -r motd_path; do + motd_path=${motd_path#\"}; motd_path=${motd_path%\"} + motd_path=${motd_path#\'}; motd_path=${motd_path%\'} + [[ -f "$motd_path" ]] || continue + sed -ri 's/\\[vrms]//g; s/(Ubuntu|Debian|GNU\/Linux)//Ig' "$motd_path" + if [[ -n "$os_id" ]]; then + sed -ri "s/\\b${os_id}\\b//Ig" "$motd_path" + fi +done < <(grep -hPoi '^\h*session\h+(required|optional)\h+pam_motd\.so\b.*\bmotd=\K("[^"]+"|'"'"'[^'"'"']+'"'"'|\S+)' /etc/pam.d/* 2>/dev/null | sort -u) diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/oval/shared.xml b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/oval/shared.xml deleted file mode 100644 index 26f2bab4585b..000000000000 --- a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/oval/shared.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - {{{ oval_metadata("pam_motd uses explicit, non-disclosing message files.", rule_title=rule_title) }}} - - - - - - - - - - - - - /etc/pam.d - ^(sshd|login|su|gdm-password)$ - ^[\s]*session[\s]+[^#\n]*pam_motd\.so[^#\n]*[\s]motd=([^\s#]+).*$ - 1 - - - - - - - - - - - - - - - - - - - ^.*(\\[vrms]|(?i:Ubuntu|Debian|GNU/Linux)).*$ - 1 - - diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/sce/shared.sh b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/sce/shared.sh new file mode 100644 index 000000000000..60387e58ebd4 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/sce/shared.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# check-import = stdout + +result=$XCCDF_RESULT_PASS +found_entry=false +os_id=$(awk -F= '$1 == "ID" { gsub(/^"|"$/, "", $2); print $2; exit }' /etc/os-release 2>/dev/null) + +for service in sshd login su gdm-password; do + if [[ -f "/etc/pam.d/$service" ]]; then + pam_file="/etc/pam.d/$service" + elif [[ -f "/usr/lib/pam.d/$service" ]]; then + pam_file="/usr/lib/pam.d/$service" + else + continue + fi + + while IFS= read -r line; do + found_entry=true + motd_path=$(grep -oP '\bmotd=\K("[^"]+"|'"'"'[^'"'"']+'"'"'|\S+)' <<< "$line" | head -n 1) + motd_path=${motd_path#\"}; motd_path=${motd_path%\"} + motd_path=${motd_path#\'}; motd_path=${motd_path%\'} + + if [[ -z "$motd_path" || ! -r "$motd_path" ]]; then + echo "$pam_file: pam_motd does not reference a readable explicit motd path." + result=$XCCDF_RESULT_FAIL + continue + fi + + unsafe='(\\[vrms]|Ubuntu|Debian|GNU/Linux)' + [[ -n "$os_id" ]] && unsafe="(\\\\[vrms]|Ubuntu|Debian|GNU/Linux|${os_id})" + if grep -Piq "$unsafe" "$motd_path"; then + echo "$motd_path contains operating-system information or a prohibited escape sequence." + result=$XCCDF_RESULT_FAIL + fi + done < <(grep -Pi '^\h*session\h+(required|optional)\h+pam_motd\.so\b' "$pam_file" 2>/dev/null) +done + +if [[ "$found_entry" != true ]]; then + echo 'No active pam_motd entry with an explicit message file was found.' + result=$XCCDF_RESULT_FAIL +fi + +exit "$result" diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/explicit_safe_motd.pass.sh b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/explicit_safe_motd.pass.sh index 3cee8e3aac18..7773b297781b 100644 --- a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/explicit_safe_motd.pass.sh +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/explicit_safe_motd.pass.sh @@ -1,7 +1,7 @@ #!/bin/bash # platform = multi_platform_ubuntu -# Remove every pam_motd entry the check looks at, so each scenario starts clean. +# Remove pam_motd entries from every PAM file checked by this rule. for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/su /etc/pam.d/gdm-password; do [ -f "$f" ] && sed -ri '/pam_motd\.so/d' "$f" done diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/motd_discloses_os.fail.sh b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/motd_discloses_os.fail.sh index ffeeda3b5aeb..9de132418c64 100644 --- a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/motd_discloses_os.fail.sh +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/motd_discloses_os.fail.sh @@ -1,8 +1,7 @@ #!/bin/bash # platform = multi_platform_ubuntu -# remediation = none -# Remove every pam_motd entry the check looks at, so each scenario starts clean. +# Remove pam_motd entries from every PAM file checked by this rule. for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/su /etc/pam.d/gdm-password; do [ -f "$f" ] && sed -ri '/pam_motd\.so/d' "$f" done diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/no_explicit_path.fail.sh b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/no_explicit_path.fail.sh index 08263446eef2..fce7e768e0d8 100644 --- a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/no_explicit_path.fail.sh +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/no_explicit_path.fail.sh @@ -1,11 +1,10 @@ #!/bin/bash # platform = multi_platform_ubuntu -# remediation = none -# Remove every pam_motd entry the check looks at, so each scenario starts clean. +# Remove pam_motd entries from every PAM file checked by this rule. for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/su /etc/pam.d/gdm-password; do [ -f "$f" ] && sed -ri '/pam_motd\.so/d' "$f" done -# pam_motd is used but no explicit motd= path is given. +# Configure pam_motd without the required explicit motd= path. echo 'session optional pam_motd.so noupdate' >> /etc/pam.d/sshd diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/quoted_path.pass.sh b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/quoted_path.pass.sh new file mode 100644 index 000000000000..384c335c2b69 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/quoted_path.pass.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# platform = Ubuntu 26.04 + +for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/su /etc/pam.d/gdm-password; do + [[ -f "$f" ]] && sed -ri '/pam_motd\.so/d' "$f" +done +printf 'Authorized use only.\n' > /etc/motd.cac +echo 'session optional pam_motd.so motd="/etc/motd.cac"' >> /etc/pam.d/sshd diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/bash/shared.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/bash/shared.sh new file mode 100644 index 000000000000..4990c46f3847 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/bash/shared.sh @@ -0,0 +1,16 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = restrict +# complexity = medium +# disruption = medium + +while IFS=: read -r user _ _ gid _ home shell; do + grep -qxF "$shell" /etc/shells 2>/dev/null || continue + [[ "$shell" == */nologin || "$shell" == */false || ! -d "$home" ]] && continue + case $(findmnt -no FSTYPE --target "$home" 2>/dev/null) in + nfs|nfs4|cifs|smbfs|smb3|fuse.sshfs|afs|ncpfs|glusterfs|ceph) continue ;; + esac + while IFS= read -r -d '' dot_dir; do + chgrp "$gid" "$dot_dir" + done < <(find "$home" -xdev -mindepth 1 -maxdepth 1 -type d -name '.*' -print0 2>/dev/null) +done < /etc/passwd diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/oval/shared.xml b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/oval/shared.xml deleted file mode 100644 index 53de4d047481..000000000000 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/oval/shared.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - {{{ oval_metadata("Interactive user dot directories have valid group owners.", rule_title=rule_title) }}} - - - - - {{%- set home_dirs_object = "object_" ~ rule_id ~ "_home_dirs" -%}} - {{{ create_local_interactive_users_home_dirs_list_object(home_dirs_object) }}} - {{%- set gids_object = "object_" ~ rule_id ~ "_gids" -%}} - {{{ create_local_interactive_users_gids_list_object(gids_object) }}} - - - - - - - - - - - - - - ^\..* - state_{{{ rule_id }}}_directory - - - directory - - - - - diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/rule.yml b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/rule.yml index 07114647d452..58d6cfbea90a 100644 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/rule.yml +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/rule.yml @@ -3,8 +3,8 @@ documentation_complete: true title: 'Configure Local Interactive User Dot Directory Group Ownership' description: |- - Dot directories below local interactive user home directories must be - group-owned by a local interactive user's primary group. + Dot directories below each local interactive user's home directory must be + group-owned by that user's primary group. rationale: |- Unexpected group ownership can expose private user configuration and @@ -16,7 +16,7 @@ platform: system_with_kernel ocil_clause: 'a dot directory has an unexpected group owner' -warnings: - - general: |- - Due to an OVAL limitation, swapped group ownership between two - interactive users can produce a false negative. +ocil: |- + For each local interactive user, recursively inspect dot directories on the + local filesystem below that user's home directory. Every directory must be + group-owned by that user's primary group. diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/sce/shared.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/sce/shared.sh new file mode 100644 index 000000000000..0480e42386b9 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/sce/shared.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# check-import = stdout + +result=$XCCDF_RESULT_PASS +while IFS=: read -r user _ _ gid _ home shell; do + grep -qxF "$shell" /etc/shells 2>/dev/null || continue + [[ "$shell" == */nologin || "$shell" == */false || ! -d "$home" ]] && continue + case $(findmnt -no FSTYPE --target "$home" 2>/dev/null) in + nfs|nfs4|cifs|smbfs|smb3|fuse.sshfs|afs|ncpfs|glusterfs|ceph) continue ;; + esac + while IFS= read -r -d '' dot_dir; do + owner_gid=$(stat -Lc '%g' "$dot_dir") + if [[ "$owner_gid" != "$gid" ]]; then + echo "$dot_dir is group-owned by GID $owner_gid; expected $gid for $user." + result=$XCCDF_RESULT_FAIL + fi + done < <(find "$home" -xdev -mindepth 1 -maxdepth 1 -type d -name '.*' -print0 2>/dev/null) +done < /etc/passwd +exit "$result" diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/expected_owner.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/expected_owner.pass.sh index cb41b9bb97d3..f90b8303d084 100644 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/expected_owner.pass.sh +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/expected_owner.pass.sh @@ -1,4 +1,5 @@ #!/bin/bash +# platform = Ubuntu 26.04 USER="cac_user" useradd -m $USER diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/swapped_group_owners.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/swapped_group_owners.fail.sh new file mode 100644 index 000000000000..bb7d00b8fdaf --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/swapped_group_owners.fail.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# platform = Ubuntu 26.04 + +USER1="cac_user1" +USER2="cac_user2" +useradd -m $USER1 +useradd -m $USER2 +mkdir -p /home/$USER1/.config +chgrp -R "$(id -g $USER2)" /home/$USER1/.config diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/unexpected_owner_system_id.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/unexpected_owner_system_id.fail.sh index fca8df3db0d3..b5e490a9043b 100644 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/unexpected_owner_system_id.fail.sh +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/unexpected_owner_system_id.fail.sh @@ -1,5 +1,5 @@ #!/bin/bash -# remediation = none +# platform = Ubuntu 26.04 USER="cac_user" useradd -m $USER diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/warning_swapped_group_owners.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/warning_swapped_group_owners.pass.sh deleted file mode 100644 index c6c720bfa631..000000000000 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_groupownership/tests/warning_swapped_group_owners.pass.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# Documents the limitation recorded in the rule's warnings block: a dot directory -# belonging to one interactive user but group ownered by another still passes, because the -# check only requires an interactive user's id. -USER1="cac_user1" -USER2="cac_user2" -useradd -m $USER1 -useradd -m $USER2 -mkdir -p /home/$USER1/.config -chgrp -R "$(id -g $USER2)" /home/$USER1/.config diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/bash/shared.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/bash/shared.sh new file mode 100644 index 000000000000..3cc01d15f8c5 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/bash/shared.sh @@ -0,0 +1,16 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = restrict +# complexity = medium +# disruption = medium + +while IFS=: read -r user _ _ _ _ home shell; do + grep -qxF "$shell" /etc/shells 2>/dev/null || continue + [[ "$shell" == */nologin || "$shell" == */false || ! -d "$home" ]] && continue + case $(findmnt -no FSTYPE --target "$home" 2>/dev/null) in + nfs|nfs4|cifs|smbfs|smb3|fuse.sshfs|afs|ncpfs|glusterfs|ceph) continue ;; + esac + while IFS= read -r -d '' dot_dir; do + chown "$user" "$dot_dir" + done < <(find "$home" -xdev -mindepth 1 -maxdepth 1 -type d -name '.*' -print0 2>/dev/null) +done < /etc/passwd diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/oval/shared.xml b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/oval/shared.xml deleted file mode 100644 index 48d40094b941..000000000000 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/oval/shared.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - {{{ oval_metadata("Interactive user dot directories have valid owners.", rule_title=rule_title) }}} - - - - - {{%- set home_dirs_object = "object_" ~ rule_id ~ "_home_dirs" -%}} - {{{ create_local_interactive_users_home_dirs_list_object(home_dirs_object) }}} - {{%- set uids_object = "object_" ~ rule_id ~ "_uids" -%}} - {{{ create_local_interactive_users_uids_list_object(uids_object) }}} - - - - - - - - - - - - - - ^\..* - state_{{{ rule_id }}}_directory - - - directory - - - - - diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/rule.yml b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/rule.yml index 142d25521715..6065b352c25f 100644 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/rule.yml +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/rule.yml @@ -3,8 +3,8 @@ documentation_complete: true title: 'Configure Local Interactive User Dot Directory Ownership' description: |- - Dot directories below local interactive user home directories must be owned - by a local interactive user. + Dot directories below each local interactive user's home directory must be + owned by that user. rationale: |- Unexpected ownership can allow one account to control another account's @@ -16,7 +16,7 @@ platform: system_with_kernel ocil_clause: 'a dot directory has an unexpected owner' -warnings: - - general: |- - Due to an OVAL limitation, swapped ownership between two interactive - users can produce a false negative. +ocil: |- + For each local interactive user, recursively inspect dot directories on the + local filesystem below that user's home directory. Every directory must be + owned by that user. diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/sce/shared.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/sce/shared.sh new file mode 100644 index 000000000000..9c0ec988f4de --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/sce/shared.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# check-import = stdout + +result=$XCCDF_RESULT_PASS +while IFS=: read -r user _ uid _ _ home shell; do + grep -qxF "$shell" /etc/shells 2>/dev/null || continue + [[ "$shell" == */nologin || "$shell" == */false || ! -d "$home" ]] && continue + case $(findmnt -no FSTYPE --target "$home" 2>/dev/null) in + nfs|nfs4|cifs|smbfs|smb3|fuse.sshfs|afs|ncpfs|glusterfs|ceph) continue ;; + esac + while IFS= read -r -d '' dot_dir; do + owner_uid=$(stat -Lc '%u' "$dot_dir") + if [[ "$owner_uid" != "$uid" ]]; then + echo "$dot_dir is owned by UID $owner_uid; expected $uid ($user)." + result=$XCCDF_RESULT_FAIL + fi + done < <(find "$home" -xdev -mindepth 1 -maxdepth 1 -type d -name '.*' -print0 2>/dev/null) +done < /etc/passwd +exit "$result" diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/expected_owner.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/expected_owner.pass.sh index 88a611cd014b..7c6374400b6d 100644 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/expected_owner.pass.sh +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/expected_owner.pass.sh @@ -1,4 +1,5 @@ #!/bin/bash +# platform = Ubuntu 26.04 USER="cac_user" useradd -m $USER diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/swapped_owners.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/swapped_owners.fail.sh new file mode 100644 index 000000000000..faa6bc1a2496 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/swapped_owners.fail.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# platform = Ubuntu 26.04 + +USER1="cac_user1" +USER2="cac_user2" +useradd -m $USER1 +useradd -m $USER2 +mkdir -p /home/$USER1/.config +chown -R $USER2 /home/$USER1/.config diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/unexpected_owner_system_id.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/unexpected_owner_system_id.fail.sh index 37d4a1a8bcaf..0726e0c52221 100644 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/unexpected_owner_system_id.fail.sh +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/unexpected_owner_system_id.fail.sh @@ -1,5 +1,5 @@ #!/bin/bash -# remediation = none +# platform = Ubuntu 26.04 USER="cac_user" useradd -m $USER diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/warning_swapped_owners.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/warning_swapped_owners.pass.sh deleted file mode 100644 index 1db07c618cba..000000000000 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_ownership/tests/warning_swapped_owners.pass.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# Documents the limitation recorded in the rule's warnings block: a dot directory -# belonging to one interactive user but ownered by another still passes, because the -# check only requires an interactive user's id. -USER1="cac_user1" -USER2="cac_user2" -useradd -m $USER1 -useradd -m $USER2 -mkdir -p /home/$USER1/.config -chown -R $USER2 /home/$USER1/.config diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/bash/shared.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/bash/shared.sh new file mode 100644 index 000000000000..b2c625b45be5 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/bash/shared.sh @@ -0,0 +1,20 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = restrict +# complexity = medium +# disruption = medium + +while IFS=: read -r _ _ _ _ _ home shell; do + grep -qxF "$shell" /etc/shells 2>/dev/null || continue + [[ "$shell" == */nologin || "$shell" == */false || ! -d "$home" ]] && continue + case $(findmnt -no FSTYPE --target "$home" 2>/dev/null) in + nfs|nfs4|cifs|smbfs|smb3|fuse.sshfs|afs|ncpfs|glusterfs|ceph) continue ;; + esac + while IFS= read -r -d '' dot_dir; do + if [[ ${dot_dir##*/} == .ssh ]]; then + chmod go-rwx "$dot_dir" + else + chmod g-w,o-rwx "$dot_dir" + fi + done < <(find "$home" -xdev -mindepth 1 -maxdepth 1 -type d -name '.*' -print0 2>/dev/null) +done < /etc/passwd diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/oval/shared.xml b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/oval/shared.xml deleted file mode 100644 index 8bc1931099bd..000000000000 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/oval/shared.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - {{{ oval_metadata("Interactive user dot directories have restrictive permissions.", rule_title=rule_title) }}} - - - - - - - {{%- set home_dirs_object = "object_" ~ rule_id ~ "_home_dirs" -%}} - {{{ create_local_interactive_users_home_dirs_list_object(home_dirs_object) }}} - - - - - - - - - - - - ^\..* - state_{{{ rule_id }}}_directory - - - - - - - - - - .ssh - state_{{{ rule_id }}}_directory - - - - directory - - - false - false - false - false - - - false - false - false - false - false - false - - diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/sce/shared.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/sce/shared.sh new file mode 100644 index 000000000000..f5594999f9bd --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/sce/shared.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# check-import = stdout + +result=$XCCDF_RESULT_PASS +while IFS=: read -r _ _ _ _ _ home shell; do + grep -qxF "$shell" /etc/shells 2>/dev/null || continue + [[ "$shell" == */nologin || "$shell" == */false || ! -d "$home" ]] && continue + case $(findmnt -no FSTYPE --target "$home" 2>/dev/null) in + nfs|nfs4|cifs|smbfs|smb3|fuse.sshfs|afs|ncpfs|glusterfs|ceph) continue ;; + esac + while IFS= read -r -d '' dot_dir; do + mode=$(stat -Lc '%a' "$dot_dir") + mask=0027 + [[ ${dot_dir##*/} == .ssh ]] && mask=0077 + if (( 8#$mode & mask )); then + echo "$dot_dir has mode $mode, which is too permissive." + result=$XCCDF_RESULT_FAIL + fi + done < <(find "$home" -xdev -mindepth 1 -maxdepth 1 -type d -name '.*' -print0 2>/dev/null) +done < /etc/passwd +exit "$result" diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/group_writable_dot_dir.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/group_writable_dot_dir.fail.sh index 9b5623c31149..70792354f31c 100644 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/group_writable_dot_dir.fail.sh +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/group_writable_dot_dir.fail.sh @@ -1,5 +1,5 @@ #!/bin/bash -# remediation = none +# platform = Ubuntu 26.04 USER="cac_user" useradd -m $USER diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/restrictive_modes.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/restrictive_modes.pass.sh index 8b5f7e7fdf53..b35792900df2 100644 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/restrictive_modes.pass.sh +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/restrictive_modes.pass.sh @@ -1,4 +1,5 @@ #!/bin/bash +# platform = Ubuntu 26.04 USER="cac_user" useradd -m $USER diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/world_readable_ssh_dir.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/world_readable_ssh_dir.fail.sh index 85adf1bdd908..9a6b95aa5583 100644 --- a/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/world_readable_ssh_dir.fail.sh +++ b/linux_os/guide/system/accounts/accounts-session/accounts_user_dot_dirs_permissions/tests/world_readable_ssh_dir.fail.sh @@ -1,5 +1,5 @@ #!/bin/bash -# remediation = none +# platform = Ubuntu 26.04 USER="cac_user" useradd -m $USER From 42e79b325c6d627fe5e6f22fe5d9e40275eb21d9 Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 15:31:16 +1200 Subject: [PATCH 09/18] Complete Ubuntu 26.04 package and service remediations --- .../bash/shared.sh | 13 ++++++---- .../tests/unit_absent.pass.sh | 4 ++++ .../bash/shared.sh | 13 ++++++---- .../rule.yml | 9 +++---- .../tests/timer_disabled.pass.sh | 7 ++++++ .../tests/unit_absent.pass.sh | 4 ++++ .../bash/shared.sh | 24 ++++++++++++++++++- .../ansible/shared.yml | 11 +++++++++ .../bash/shared.sh | 7 ++++++ .../rule.yml | 9 +++---- .../sce/shared.sh | 15 ++++++++++++ .../tests/installed_latest.pass.sh | 5 ++++ .../tests/missing.fail.sh | 4 ++++ 13 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 linux_os/guide/services/base/service_update-notifier-motd_disabled/tests/unit_absent.pass.sh create mode 100644 linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/timer_disabled.pass.sh create mode 100644 linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/unit_absent.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/ansible/shared.yml create mode 100644 linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/bash/shared.sh create mode 100644 linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/sce/shared.sh create mode 100644 linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/tests/installed_latest.pass.sh create mode 100644 linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/tests/missing.fail.sh diff --git a/linux_os/guide/services/base/service_update-notifier-motd_disabled/bash/shared.sh b/linux_os/guide/services/base/service_update-notifier-motd_disabled/bash/shared.sh index 0c95f1a1c4d4..dc51db2f506c 100644 --- a/linux_os/guide/services/base/service_update-notifier-motd_disabled/bash/shared.sh +++ b/linux_os/guide/services/base/service_update-notifier-motd_disabled/bash/shared.sh @@ -5,9 +5,12 @@ # disruption = low SYSTEMCTL_EXEC=/usr/bin/systemctl -if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then - "$SYSTEMCTL_EXEC" stop update-notifier-motd.service +unit=update-notifier-motd.service +if "$SYSTEMCTL_EXEC" list-unit-files "$unit" --no-legend 2>/dev/null | grep -q "^${unit}[[:space:]]"; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop "$unit" + fi + "$SYSTEMCTL_EXEC" disable "$unit" + "$SYSTEMCTL_EXEC" mask "$unit" + "$SYSTEMCTL_EXEC" reset-failed "$unit" || true fi -"$SYSTEMCTL_EXEC" disable update-notifier-motd.service -"$SYSTEMCTL_EXEC" mask update-notifier-motd.service -"$SYSTEMCTL_EXEC" reset-failed update-notifier-motd.service || true diff --git a/linux_os/guide/services/base/service_update-notifier-motd_disabled/tests/unit_absent.pass.sh b/linux_os/guide/services/base/service_update-notifier-motd_disabled/tests/unit_absent.pass.sh new file mode 100644 index 000000000000..eabe1e59ffa1 --- /dev/null +++ b/linux_os/guide/services/base/service_update-notifier-motd_disabled/tests/unit_absent.pass.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# platform = Ubuntu 26.04 + +{{{ bash_package_remove("update-notifier-common") }}} diff --git a/linux_os/guide/services/base/timer_update-notifier-motd_disabled/bash/shared.sh b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/bash/shared.sh index c3d3bf6a1a38..bcf632d4b7e1 100644 --- a/linux_os/guide/services/base/timer_update-notifier-motd_disabled/bash/shared.sh +++ b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/bash/shared.sh @@ -5,9 +5,12 @@ # disruption = low SYSTEMCTL_EXEC=/usr/bin/systemctl -if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then - "$SYSTEMCTL_EXEC" stop update-notifier-motd.timer +unit=update-notifier-motd.timer +if "$SYSTEMCTL_EXEC" list-unit-files "$unit" --no-legend 2>/dev/null | grep -q "^${unit}[[:space:]]"; then + if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then + "$SYSTEMCTL_EXEC" stop "$unit" + fi + "$SYSTEMCTL_EXEC" disable "$unit" + "$SYSTEMCTL_EXEC" mask "$unit" + "$SYSTEMCTL_EXEC" reset-failed "$unit" || true fi -"$SYSTEMCTL_EXEC" disable update-notifier-motd.timer -"$SYSTEMCTL_EXEC" mask update-notifier-motd.timer -"$SYSTEMCTL_EXEC" reset-failed update-notifier-motd.timer || true diff --git a/linux_os/guide/services/base/timer_update-notifier-motd_disabled/rule.yml b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/rule.yml index 245ee1bbf5b4..460ff391533d 100644 --- a/linux_os/guide/services/base/timer_update-notifier-motd_disabled/rule.yml +++ b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/rule.yml @@ -3,8 +3,9 @@ documentation_complete: true title: 'Disable and Mask update-notifier-motd Timer' description: |- - The update-notifier-motd.timer unit must be stopped, disabled, and masked - when the update-notifier-common package is installed. + The update-notifier-motd.timer unit must be inactive and not enabled when + the update-notifier-common package is installed. Masking is the preferred + remediation because it also prevents transient activation. rationale: |- Disabling the timer prevents periodic regeneration of dynamic login @@ -14,9 +15,9 @@ severity: medium platform: system_with_kernel -ocil_clause: 'update-notifier-motd.timer is active or is not masked' +ocil_clause: 'update-notifier-motd.timer is active or enabled' ocil: |- Run systemctl is-active update-notifier-motd.timer and systemctl is-enabled update-notifier-motd.timer. The timer must be - inactive and masked, or the update-notifier-common package must be absent. + inactive and not enabled, or the update-notifier-common package must be absent. diff --git a/linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/timer_disabled.pass.sh b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/timer_disabled.pass.sh new file mode 100644 index 000000000000..c24cddcbed9f --- /dev/null +++ b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/timer_disabled.pass.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# packages = update-notifier-common + +systemctl stop update-notifier-motd.timer 2>/dev/null || true +systemctl disable update-notifier-motd.timer 2>/dev/null || true +systemctl unmask update-notifier-motd.timer 2>/dev/null || true diff --git a/linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/unit_absent.pass.sh b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/unit_absent.pass.sh new file mode 100644 index 000000000000..eabe1e59ffa1 --- /dev/null +++ b/linux_os/guide/services/base/timer_update-notifier-motd_disabled/tests/unit_absent.pass.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# platform = Ubuntu 26.04 + +{{{ bash_package_remove("update-notifier-common") }}} diff --git a/linux_os/guide/services/ntp/chronyd_specify_remote_server/bash/shared.sh b/linux_os/guide/services/ntp/chronyd_specify_remote_server/bash/shared.sh index 5362980d00be..ed11af52a90f 100644 --- a/linux_os/guide/services/ntp/chronyd_specify_remote_server/bash/shared.sh +++ b/linux_os/guide/services/ntp/chronyd_specify_remote_server/bash/shared.sh @@ -4,6 +4,28 @@ config_file="{{{ chrony_conf_path }}}" -if ! grep -q '^[[:space:]]*\(server\|pool\)[[:space:]]\+[[:graph:]]\+' "$config_file" ; then +has_remote_source=false +if grep -q '^[[:space:]]*\(server\|pool\)[[:space:]]\+[[:graph:]]\+' "$config_file" 2>/dev/null; then + has_remote_source=true +fi + +while [[ "$has_remote_source" == false ]] && read -r directive location _; do + [[ "$directive" == sourcedir || "$directive" == confdir ]] || continue + extension='*.conf' + [[ "$directive" == sourcedir ]] && extension='*.sources' + while IFS= read -r -d '' include_file; do + if grep -q '^[[:space:]]*\(server\|pool\)[[:space:]]\+[[:graph:]]\+' "$include_file"; then + has_remote_source=true + break + fi + done < <(find -L "$location" -maxdepth 1 -type f -name "$extension" -print0 2>/dev/null) +done < "$config_file" + +if [[ "$has_remote_source" == false ]]; then + sourcedir=$(awk '$1 == "sourcedir" { print $2; exit }' "$config_file") + if [[ -n "$sourcedir" ]]; then + mkdir -p "$sourcedir" + config_file="$sourcedir/60-cis.sources" + fi {{{ bash_ensure_there_are_servers_in_ntp_compatible_config_file("$config_file", "$var_multiple_time_servers") | indent(2) }}} fi diff --git a/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/ansible/shared.yml b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/ansible/shared.yml new file mode 100644 index 000000000000..ab10c451d018 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/ansible/shared.yml @@ -0,0 +1,11 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = enable +# complexity = low +# disruption = low + +- name: Install the latest cracklib-runtime package + ansible.builtin.apt: + name: cracklib-runtime + state: latest + update_cache: false diff --git a/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/bash/shared.sh b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/bash/shared.sh new file mode 100644 index 000000000000..95b845313fc4 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/bash/shared.sh @@ -0,0 +1,7 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = enable +# complexity = low +# disruption = low + +DEBIAN_FRONTEND=noninteractive apt-get install -y cracklib-runtime diff --git a/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/rule.yml b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/rule.yml index 97bf501a4096..5be2e4925dfe 100644 --- a/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/rule.yml +++ b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/rule.yml @@ -11,7 +11,8 @@ rationale: |- severity: medium -template: - name: package_installed - vars: - pkgname: cracklib-runtime +ocil_clause: 'cracklib-runtime is not installed or an upgrade is available' + +ocil: |- + Verify dpkg-query -s cracklib-runtime succeeds and + apt list --upgradable does not list cracklib-runtime. diff --git a/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/sce/shared.sh b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/sce/shared.sh new file mode 100644 index 000000000000..d85036657e56 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/sce/shared.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# check-import = stdout + +if ! dpkg-query -W -f='${db:Status-Status}\n' cracklib-runtime 2>/dev/null | grep -qx installed; then + echo 'cracklib-runtime is not installed.' + exit "$XCCDF_RESULT_FAIL" +fi + +if apt list --upgradable 2>/dev/null | grep -Pq '^cracklib-runtime/'; then + echo 'An upgrade is available for cracklib-runtime.' + exit "$XCCDF_RESULT_FAIL" +fi + +exit "$XCCDF_RESULT_PASS" diff --git a/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/tests/installed_latest.pass.sh b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/tests/installed_latest.pass.sh new file mode 100644 index 000000000000..646d68d52935 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/tests/installed_latest.pass.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# packages = cracklib-runtime + +exit 0 diff --git a/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/tests/missing.fail.sh b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/tests/missing.fail.sh new file mode 100644 index 000000000000..690d1c411fd6 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-pam/package_cracklib-runtime_installed/tests/missing.fail.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# platform = Ubuntu 26.04 + +{{{ bash_package_remove("cracklib-runtime") }}} From 7cda1e7d4c3c6f96f210bb12c325828bd243c003 Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 15:31:23 +1200 Subject: [PATCH 10/18] Correct Ubuntu 26.04 CIS Level 1 profile wiring --- products/ubuntu2604/controls/cis_ubuntu2604.yml | 8 +++----- products/ubuntu2604/profiles/cis_level1_server.profile | 4 ++++ .../ubuntu2604/profiles/cis_level1_workstation.profile | 4 ++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/products/ubuntu2604/controls/cis_ubuntu2604.yml b/products/ubuntu2604/controls/cis_ubuntu2604.yml index e9dda51704a2..5a10045eb475 100644 --- a/products/ubuntu2604/controls/cis_ubuntu2604.yml +++ b/products/ubuntu2604/controls/cis_ubuntu2604.yml @@ -600,7 +600,6 @@ controls: title: Ensure update-notifier-motd.timer is not in use (Automated) levels: - l1_server - - l1_workstation rules: - timer_update-notifier-motd_disabled status: automated @@ -1446,7 +1445,7 @@ controls: - sshd_idle_timeout_value=5_minutes - var_sshd_set_keepalive=3 - sshd_set_idle_timeout - - sshd_set_keepalive + - sshd_set_keepalive_positive status: partial - id: 5.1.9 title: Ensure sshd DisableForwarding is enabled (Automated) @@ -1486,8 +1485,7 @@ controls: - l1_server - l1_workstation rules: - - sshd_strong_kex=cis_ubuntu2604 - - sshd_use_strong_kex + - sshd_use_strong_kex_ubuntu2604 status: automated - id: 5.1.14 title: Ensure sshd post-quantum key exchange algorithms are configured (Manual) @@ -1552,7 +1550,7 @@ controls: - l1_server - l1_workstation rules: - - sshd_disable_empty_passwords + - sshd_disable_empty_passwords_default status: automated - id: 5.1.22 title: Ensure sshd PermitRootLogin is disabled (Automated) diff --git a/products/ubuntu2604/profiles/cis_level1_server.profile b/products/ubuntu2604/profiles/cis_level1_server.profile index c266000f14d9..02b99c7b3af4 100644 --- a/products/ubuntu2604/profiles/cis_level1_server.profile +++ b/products/ubuntu2604/profiles/cis_level1_server.profile @@ -3,6 +3,10 @@ documentation_complete: true metadata: version: 1.0.0 + SMEs: + - mpurg + - dodys + - alanmcanonical reference: https://www.cisecurity.org/benchmark/ubuntu_linux diff --git a/products/ubuntu2604/profiles/cis_level1_workstation.profile b/products/ubuntu2604/profiles/cis_level1_workstation.profile index afd7acced97f..ed0652c04599 100644 --- a/products/ubuntu2604/profiles/cis_level1_workstation.profile +++ b/products/ubuntu2604/profiles/cis_level1_workstation.profile @@ -3,6 +3,10 @@ documentation_complete: true metadata: version: 1.0.0 + SMEs: + - mpurg + - dodys + - alanmcanonical reference: https://www.cisecurity.org/benchmark/ubuntu_linux From 55cf17809ff5899c8f619597a87d5bd28e1715b5 Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 22:31:42 +1200 Subject: [PATCH 11/18] Fix Ubuntu 26.04 SSH rule dependency --- .../services/ssh/ssh_server/sshd_set_idle_timeout/rule.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_set_idle_timeout/rule.yml b/linux_os/guide/services/ssh/ssh_server/sshd_set_idle_timeout/rule.yml index b3129efba1b9..a027e92cd4a8 100644 --- a/linux_os/guide/services/ssh/ssh_server/sshd_set_idle_timeout/rule.yml +++ b/linux_os/guide/services/ssh/ssh_server/sshd_set_idle_timeout/rule.yml @@ -55,7 +55,11 @@ references: stigid@sle12: SLES-12-030190 requires: +{{% if product == "ubuntu2604" %}} + - sshd_set_keepalive_positive +{{% else %}} - sshd_set_keepalive +{{% endif %}} ocil_clause: 'it is commented out or not configured properly' From c11a05d5a13020b7f4e005f39cc9dd96fe7d950a Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 23:29:54 +1200 Subject: [PATCH 12/18] Fix Ubuntu 26.04 account and log checks --- .../file_groupowner_backup_etc_gshadow/rule.yml | 1 + .../file_permissions_backup_etc_gshadow/rule.yml | 1 + .../file_permissions_backup_etc_shadow/rule.yml | 1 + .../file_permissions_etc_gshadow/rule.yml | 1 + .../file_permissions_etc_shadow/rule.yml | 1 + .../system/permissions/files/permissions_local_var_log/rule.yml | 2 ++ .../permissions_local_var_log/tests/excluded_files.pass.sh | 2 +- .../tests/excluded_files_similar.fail.sh | 2 +- 8 files changed, 9 insertions(+), 2 deletions(-) diff --git a/linux_os/guide/system/permissions/files/permissions_important_account_files/file_groupowner_backup_etc_gshadow/rule.yml b/linux_os/guide/system/permissions/files/permissions_important_account_files/file_groupowner_backup_etc_gshadow/rule.yml index 1133e78ccc3a..bf754ff3453a 100644 --- a/linux_os/guide/system/permissions/files/permissions_important_account_files/file_groupowner_backup_etc_gshadow/rule.yml +++ b/linux_os/guide/system/permissions/files/permissions_important_account_files/file_groupowner_backup_etc_gshadow/rule.yml @@ -49,3 +49,4 @@ template: gid_or_name@debian12: '42' gid_or_name@ubuntu2204: '42' gid_or_name@ubuntu2404: shadow + gid_or_name@ubuntu2604: shadow diff --git a/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_backup_etc_gshadow/rule.yml b/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_backup_etc_gshadow/rule.yml index f988368aae7c..e7b0bf33c258 100644 --- a/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_backup_etc_gshadow/rule.yml +++ b/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_backup_etc_gshadow/rule.yml @@ -52,3 +52,4 @@ template: filemode@debian12: '0640' filemode@ubuntu2204: '0640' filemode@ubuntu2404: '0640' + filemode@ubuntu2604: '0640' diff --git a/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_backup_etc_shadow/rule.yml b/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_backup_etc_shadow/rule.yml index b3e300599f20..92e8e0c764df 100644 --- a/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_backup_etc_shadow/rule.yml +++ b/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_backup_etc_shadow/rule.yml @@ -55,6 +55,7 @@ template: filemode@debian12: '0640' filemode@ubuntu2204: '0640' filemode@ubuntu2404: '0640' + filemode@ubuntu2604: '0640' filemode@sle12: '0640' filemode@sle15: '0640' filemode@sle16: '0640' diff --git a/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_etc_gshadow/rule.yml b/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_etc_gshadow/rule.yml index ba2d383c9416..5fb572ec3eb4 100644 --- a/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_etc_gshadow/rule.yml +++ b/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_etc_gshadow/rule.yml @@ -61,3 +61,4 @@ template: filemode@debian13: '0640' filemode@ubuntu2204: '0640' filemode@ubuntu2404: '0640' + filemode@ubuntu2604: '0640' diff --git a/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_etc_shadow/rule.yml b/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_etc_shadow/rule.yml index 4dc4175e98e1..2e0e37f28f65 100644 --- a/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_etc_shadow/rule.yml +++ b/linux_os/guide/system/permissions/files/permissions_important_account_files/file_permissions_etc_shadow/rule.yml @@ -73,3 +73,4 @@ template: filemode@sle16: '0640' filemode@ubuntu2204: '0640' filemode@ubuntu2404: '0640' + filemode@ubuntu2604: '0640' diff --git a/linux_os/guide/system/permissions/files/permissions_local_var_log/rule.yml b/linux_os/guide/system/permissions/files/permissions_local_var_log/rule.yml index daae0440207a..896e077fdbc3 100644 --- a/linux_os/guide/system/permissions/files/permissions_local_var_log/rule.yml +++ b/linux_os/guide/system/permissions/files/permissions_local_var_log/rule.yml @@ -58,6 +58,7 @@ template: excluded_files@ubuntu2204: ['history.log*', 'eipp.log.xz*', '[bw]tmp', '[bw]tmp.*', '[bw]tmp-*', 'lastlog', 'lastlog.*'] excluded_files@debian13: ['history.log*', 'eipp.log.xz*', '[bw]tmp', '[bw]tmp.*', '[bw]tmp-*', 'lastlog', 'lastlog.*'] excluded_files@ubuntu2404: ['history.log*', 'eipp.log.xz*', '[bw]tmp', '[bw]tmp.*', '[bw]tmp-*', 'lastlog', 'lastlog.*', 'cloud-init.log*', 'localmessages*', 'waagent.log*'] + excluded_files@ubuntu2604: ['history.log*', 'eipp.log.xz*', '[bw]tmp', '[bw]tmp.*', '[bw]tmp-*', 'lastlog', 'lastlog.*', 'cloud-init.log*', 'localmessages*', 'waagent.log*'] file_regex: '.*' filemode: '0640' filepath: /var/log/ @@ -69,3 +70,4 @@ template: recursive@slmicro6: 'true' recursive@ubuntu2204: 'true' recursive@ubuntu2404: 'true' + recursive@ubuntu2604: 'true' diff --git a/linux_os/guide/system/permissions/files/permissions_local_var_log/tests/excluded_files.pass.sh b/linux_os/guide/system/permissions/files/permissions_local_var_log/tests/excluded_files.pass.sh index f31fb2d11fba..3e0ee5c1f532 100644 --- a/linux_os/guide/system/permissions/files/permissions_local_var_log/tests/excluded_files.pass.sh +++ b/linux_os/guide/system/permissions/files/permissions_local_var_log/tests/excluded_files.pass.sh @@ -4,7 +4,7 @@ find /var/log -exec chmod g-rwx,o-rwx {} \; {{% if product in ['ubuntu2204'] %}} excluded_files=('history.log' 'eipp.log.xz' 'btmp' 'btmp.1' 'btmp-1' 'wtmp' 'wtmp.1' 'wtmp-1' 'lastlog' 'lastlog.1') -{{% elif product in ['ubuntu2404'] %}} +{{% elif product in ['ubuntu2404', 'ubuntu2604'] %}} excluded_files=('btmp' 'btmp.1' 'btmp-1' 'wtmp' 'wtmp.1' 'wtmp-1' 'lastlog' 'lastlog.1'\ 'cloud-init.log' 'cloud-init.log2' 'localmessages' 'localmessages2' 'waagent.log' 'waagent.log2') {{% elif product in ['sle12', 'sle15'] %}} diff --git a/linux_os/guide/system/permissions/files/permissions_local_var_log/tests/excluded_files_similar.fail.sh b/linux_os/guide/system/permissions/files/permissions_local_var_log/tests/excluded_files_similar.fail.sh index 894c22dc3750..c541716a1118 100644 --- a/linux_os/guide/system/permissions/files/permissions_local_var_log/tests/excluded_files_similar.fail.sh +++ b/linux_os/guide/system/permissions/files/permissions_local_var_log/tests/excluded_files_similar.fail.sh @@ -4,7 +4,7 @@ find /var/log -exec chmod g-rwx,o-rwx {} \; {{% if product in ['ubuntu2204'] %}} excluded_files=('2history.log' '2eipp.log.xz' 'btmp1' 'wtmp1' 'lastlog1') -{{% elif product in ['ubuntu2404'] %}} +{{% elif product in ['ubuntu2404', 'ubuntu2604'] %}} excluded_files=('btmp1' 'wtmp1' 'lastlog1' '2cloud-init.log''2localmessages' '2waagent.log') {{% elif product in ['sle12', 'sle15'] %}} excluded_files=('btmp.1', 'wtmp.1', 'lastlog.1') From f6393263728d1b7e73bfad5472be19ecfa25487b Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 23:29:54 +1200 Subject: [PATCH 13/18] Scope Ubuntu 26.04 SSH access checks --- .../services/ssh/ssh_server/sshd_limit_user_access/rule.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux_os/guide/services/ssh/ssh_server/sshd_limit_user_access/rule.yml b/linux_os/guide/services/ssh/ssh_server/sshd_limit_user_access/rule.yml index 45268c1823fc..20a00d1fc2e0 100644 --- a/linux_os/guide/services/ssh/ssh_server/sshd_limit_user_access/rule.yml +++ b/linux_os/guide/services/ssh/ssh_server/sshd_limit_user_access/rule.yml @@ -34,6 +34,10 @@ rationale: |- severity: unknown +{{% if product == "ubuntu2604" %}} +platform: package[openssh-server] +{{% endif %}} + ocil_clause: 'sshd does not limit the users who can log in' ocil: |- From 98862bf027faccb3459ce9c2716d7b08e38c8aa9 Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 23:29:54 +1200 Subject: [PATCH 14/18] Handle Ubuntu 26.04 systemd tmp mounts --- .../ansible/ubuntu2604.yml | 51 +++++++++++++++++++ .../bash/ubuntu2604.sh | 35 +++++++++++++ .../mount_option_tmp_noexec/rule.yml | 12 +++++ 3 files changed, 98 insertions(+) create mode 100644 linux_os/guide/system/permissions/partitions/mount_option_tmp_noexec/ansible/ubuntu2604.yml create mode 100644 linux_os/guide/system/permissions/partitions/mount_option_tmp_noexec/bash/ubuntu2604.sh diff --git a/linux_os/guide/system/permissions/partitions/mount_option_tmp_noexec/ansible/ubuntu2604.yml b/linux_os/guide/system/permissions/partitions/mount_option_tmp_noexec/ansible/ubuntu2604.yml new file mode 100644 index 000000000000..f8b25de09171 --- /dev/null +++ b/linux_os/guide/system/permissions/partitions/mount_option_tmp_noexec/ansible/ubuntu2604.yml @@ -0,0 +1,51 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = configure +# complexity = low +# disruption = medium + +- name: Read the active tmp.mount options + ansible.builtin.command: + cmd: systemctl show tmp.mount --property=Options --value + register: tmp_mount_options + changed_when: false + check_mode: false + +- name: Require an active systemd mount definition for /tmp + ansible.builtin.assert: + that: + - tmp_mount_options.rc == 0 + - tmp_mount_options.stdout | trim | length > 0 + fail_msg: tmp.mount does not report its mount options. + +- name: Create the tmp.mount drop-in directory + ansible.builtin.file: + path: /etc/systemd/system/tmp.mount.d + state: directory + owner: root + group: root + mode: '0755' + when: "'noexec' not in (tmp_mount_options.stdout | trim).split(',')" + +- name: Add noexec to the tmp.mount options + ansible.builtin.copy: + dest: /etc/systemd/system/tmp.mount.d/99-cis-noexec.conf + content: |- + [Mount] + Options={{ tmp_mount_options.stdout | trim }},noexec + owner: root + group: root + mode: '0644' + register: tmp_mount_drop_in + when: "'noexec' not in (tmp_mount_options.stdout | trim).split(',')" + +- name: Reload systemd after changing tmp.mount + ansible.builtin.systemd_service: + daemon_reload: true + when: tmp_mount_drop_in is changed + +- name: Remount /tmp with noexec + ansible.builtin.command: + cmd: mount --options remount,noexec --target /tmp + changed_when: true + when: tmp_mount_drop_in is changed diff --git a/linux_os/guide/system/permissions/partitions/mount_option_tmp_noexec/bash/ubuntu2604.sh b/linux_os/guide/system/permissions/partitions/mount_option_tmp_noexec/bash/ubuntu2604.sh new file mode 100644 index 000000000000..97f12d28ac85 --- /dev/null +++ b/linux_os/guide/system/permissions/partitions/mount_option_tmp_noexec/bash/ubuntu2604.sh @@ -0,0 +1,35 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = configure +# complexity = low +# disruption = medium + +tmp_unit="tmp.mount" +mount_option="noexec" + +if ! systemctl is-active --quiet "$tmp_unit"; then + echo "$tmp_unit is not active; the remediation cannot preserve its mount options." >&2 + exit 1 +fi + +current_options=$(systemctl show "$tmp_unit" --property=Options --value) +if [[ -z "$current_options" ]]; then + echo "$tmp_unit does not report its mount options." >&2 + exit 1 +fi + +case ",$current_options," in + *",$mount_option,"*) + exit 0 + ;; +esac + +drop_in_dir="/etc/systemd/system/${tmp_unit}.d" +drop_in_file="${drop_in_dir}/99-cis-noexec.conf" + +install -d -m 0755 "$drop_in_dir" +printf '[Mount]\nOptions=%s,%s\n' "$current_options" "$mount_option" > "$drop_in_file" +chmod 0644 "$drop_in_file" + +systemctl daemon-reload +mount --options "remount,$mount_option" --target /tmp diff --git a/linux_os/guide/system/permissions/partitions/mount_option_tmp_noexec/rule.yml b/linux_os/guide/system/permissions/partitions/mount_option_tmp_noexec/rule.yml index d1be8719333e..2497c8b55a16 100644 --- a/linux_os/guide/system/permissions/partitions/mount_option_tmp_noexec/rule.yml +++ b/linux_os/guide/system/permissions/partitions/mount_option_tmp_noexec/rule.yml @@ -6,7 +6,12 @@ title: 'Add noexec Option to /tmp' description: |- The noexec mount option can be used to prevent binaries from being executed out of /tmp. + {{% if product == "ubuntu2604" %}} + Add noexec to the Options setting in a + tmp.mount systemd drop-in. + {{% else %}} {{{ describe_mount(option="noexec", part="/tmp") }}} + {{% endif %}} rationale: |- Allowing users to execute binaries from world-writable directories @@ -55,7 +60,14 @@ template: mountoption: noexec # Note that /tmp on RHEL systems is not tmpfs +{{% if product == "ubuntu2604" %}} +fixtext: |- + Create a systemd drop-in for tmp.mount that preserves the active + mount options and adds noexec. Reload systemd and remount + /tmp with noexec. +{{% else %}} fixtext: |- {{{ fixtext_mount_option("/tmp", "noexec") }}} +{{% endif %}} srg_requirement: '{{{ srg_requirement_mount_option("/tmp", "noexec") }}}' From 1a5c77d7bdcfebbd4a9a3258eb66244d8e018171 Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 23:59:15 +1200 Subject: [PATCH 15/18] Map Ubuntu 26.04 pam_pwquality package --- .../accounts-pam/package_pam_pwquality_installed/rule.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/linux_os/guide/system/accounts/accounts-pam/package_pam_pwquality_installed/rule.yml b/linux_os/guide/system/accounts/accounts-pam/package_pam_pwquality_installed/rule.yml index c9d08e4bb907..3b5609459328 100644 --- a/linux_os/guide/system/accounts/accounts-pam/package_pam_pwquality_installed/rule.yml +++ b/linux_os/guide/system/accounts/accounts-pam/package_pam_pwquality_installed/rule.yml @@ -40,6 +40,7 @@ template: pkgname: libpwquality pkgname@ubuntu2204: libpam-pwquality pkgname@ubuntu2404: libpam-pwquality + pkgname@ubuntu2604: libpam-pwquality pkgname@debian12: libpam-pwquality pkgname@debian13: libpam-pwquality From ddefa788b4e2c72ea3de3e8d94ecbd1b5793cdba Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sat, 5 Sep 2026 23:59:22 +1200 Subject: [PATCH 16/18] Handle Ubuntu 26.04 sudo-rs logging --- components/sudo.yml | 1 + .../ansible/shared.yml | 16 +++++++++++++ .../sudo_logging_ubuntu2604/bash/shared.sh | 9 +++++++ .../sudo/sudo_logging_ubuntu2604/rule.yml | 23 ++++++++++++++++++ .../sudo_logging_ubuntu2604/sce/shared.sh | 24 +++++++++++++++++++ .../ubuntu2604/controls/cis_ubuntu2604.yml | 2 +- 6 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/ansible/shared.yml create mode 100644 linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/bash/shared.sh create mode 100644 linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/rule.yml create mode 100644 linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/sce/shared.sh diff --git a/components/sudo.yml b/components/sudo.yml index 752c426ef8e2..1ea3c758cdd6 100644 --- a/components/sudo.yml +++ b/components/sudo.yml @@ -19,6 +19,7 @@ rules: - sudo_add_umask - sudo_add_use_pty - sudo_custom_logfile +- sudo_logging_ubuntu2604 - sudo_dedicated_group - sudo_remove_no_authenticate - sudo_remove_nopasswd diff --git a/linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/ansible/shared.yml b/linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/ansible/shared.yml new file mode 100644 index 000000000000..aeed126ce4ae --- /dev/null +++ b/linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/ansible/shared.yml @@ -0,0 +1,16 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = restrict +# complexity = low +# disruption = low + +- name: Install rsyslog for sudo event logging + ansible.builtin.package: + name: rsyslog + state: present + +- name: Enable rsyslog for sudo event logging + ansible.builtin.systemd_service: + name: rsyslog.service + enabled: true + state: started diff --git a/linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/bash/shared.sh b/linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/bash/shared.sh new file mode 100644 index 000000000000..9facdf328434 --- /dev/null +++ b/linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/bash/shared.sh @@ -0,0 +1,9 @@ +# platform = Ubuntu 26.04 +# reboot = false +# strategy = restrict +# complexity = low +# disruption = low + +{{{ bash_package_install("rsyslog") }}} + +systemctl enable --now rsyslog.service diff --git a/linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/rule.yml b/linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/rule.yml new file mode 100644 index 000000000000..8a54fe48502b --- /dev/null +++ b/linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/rule.yml @@ -0,0 +1,23 @@ +documentation_complete: true + +title: 'Ensure Sudo Events Are Logged' + +description: |- + Sudo events must be captured in a durable log. sudo-rs sends + events to the authpriv syslog facility and does not support the + classic sudo Defaults logfile= option. + +rationale: |- + A durable record of privilege escalation supports auditing and incident + investigation. + +severity: low + +platform: package[sudo] + +ocil_clause: 'sudo events are not present in the journal or a persistent log' + +ocil: |- + Run journalctl -t sudo -t sudo-rs and inspect + /var/log/auth.log. At least one location must contain sudo events. + Classic sudo may instead use a valid Defaults logfile= setting. diff --git a/linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/sce/shared.sh b/linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/sce/shared.sh new file mode 100644 index 000000000000..feb0716b763c --- /dev/null +++ b/linux_os/guide/system/software/sudo/sudo_logging_ubuntu2604/sce/shared.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# platform = Ubuntu 26.04 +# check-import = stdout + +if journalctl -q -t sudo -t sudo-rs --since=-5min --no-pager 2>/dev/null | + grep -q '[^[:space:]]'; then + exit "$XCCDF_RESULT_PASS" +fi + +if grep -Eq '\b(sudo|sudo-rs)\[[0-9]+\]:' /var/log/auth.log 2>/dev/null; then + exit "$XCCDF_RESULT_PASS" +fi + +if ! dpkg-query --show --showformat='${db:Status-Status}' sudo-rs 2>/dev/null | + grep -qx installed; then + if grep -rPsiq \ + '^\h*Defaults\h+([^#]+,\h*)?logfile\h*=\h*("|'"'"')?\H+("|'"'"')?(,\h*\H+\h*)*\h*(#.*)?$' \ + /etc/sudoers /etc/sudoers.d 2>/dev/null; then + exit "$XCCDF_RESULT_PASS" + fi +fi + +echo 'No sudo event was found in the journal or /var/log/auth.log.' +exit "$XCCDF_RESULT_FAIL" diff --git a/products/ubuntu2604/controls/cis_ubuntu2604.yml b/products/ubuntu2604/controls/cis_ubuntu2604.yml index 5a10045eb475..0611900a4898 100644 --- a/products/ubuntu2604/controls/cis_ubuntu2604.yml +++ b/products/ubuntu2604/controls/cis_ubuntu2604.yml @@ -1598,7 +1598,7 @@ controls: - l1_server - l1_workstation rules: - - sudo_custom_logfile + - sudo_logging_ubuntu2604 status: automated - id: 5.2.5 title: Ensure users must provide a password for privilege escalation (Automated) From d037f5ae29aeaf5aa0574c8331d2dc0ce89ac449 Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sun, 6 Sep 2026 12:58:42 +1200 Subject: [PATCH 17/18] Handle missing Ubuntu 26.04 PAM MOTD files --- .../pam_motd_configured/bash/shared.sh | 40 +++++++++++++------ .../tests/missing_referenced_file.fail.sh | 12 ++++++ 2 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/missing_referenced_file.fail.sh diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/bash/shared.sh b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/bash/shared.sh index 2dd68aafb014..862f8e34ba58 100644 --- a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/bash/shared.sh +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/bash/shared.sh @@ -9,18 +9,34 @@ touch /etc/motd chown root:root /etc/motd chmod u-x,go-wx /etc/motd -for service in sshd login su gdm-password; do - pam_file="/etc/pam.d/$service" +append_canonical_entry() { + local pam_file=$1 + if [[ -s "$pam_file" && -n $(tail -c 1 "$pam_file") ]]; then + printf '\n' >> "$pam_file" + fi + printf '%s\n' 'session optional pam_motd.so motd=/etc/motd' >> "$pam_file" +} + +configured=false +for pam_file in /etc/pam.d/*; do [[ -f "$pam_file" ]] || continue - sed -ri '/^[[:space:]]*session[[:space:]]+(required|optional)[[:space:]]+pam_motd\.so\b/I {/\bmotd=/! s#[[:space:]]*$# motd=/etc/motd#}' "$pam_file" + if grep -Piq '^\h*session\h+(required|optional)\h+pam_motd\.so\b' "$pam_file"; then + sed -ri '/^[[:space:]]*session[[:space:]]+(required|optional)[[:space:]]+pam_motd\.so\b/Id' "$pam_file" + append_canonical_entry "$pam_file" + configured=true + fi done -while IFS= read -r motd_path; do - motd_path=${motd_path#\"}; motd_path=${motd_path%\"} - motd_path=${motd_path#\'}; motd_path=${motd_path%\'} - [[ -f "$motd_path" ]] || continue - sed -ri 's/\\[vrms]//g; s/(Ubuntu|Debian|GNU\/Linux)//Ig' "$motd_path" - if [[ -n "$os_id" ]]; then - sed -ri "s/\\b${os_id}\\b//Ig" "$motd_path" - fi -done < <(grep -hPoi '^\h*session\h+(required|optional)\h+pam_motd\.so\b.*\bmotd=\K("[^"]+"|'"'"'[^'"'"']+'"'"'|\S+)' /etc/pam.d/* 2>/dev/null | sort -u) +if [[ "$configured" != true ]]; then + for service in sshd login su gdm-password; do + pam_file="/etc/pam.d/$service" + [[ -f "$pam_file" ]] || continue + append_canonical_entry "$pam_file" + break + done +fi + +sed -ri 's/\\[vrms]//g; s/(Ubuntu|Debian|GNU\/Linux)//Ig' /etc/motd +if [[ -n "$os_id" ]]; then + sed -ri "s/\\b${os_id}\\b//Ig" /etc/motd +fi diff --git a/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/missing_referenced_file.fail.sh b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/missing_referenced_file.fail.sh new file mode 100644 index 000000000000..f4652178c53c --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-banners/pam_motd_configured/tests/missing_referenced_file.fail.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# platform = multi_platform_ubuntu + +for f in /etc/pam.d/sshd /etc/pam.d/login /etc/pam.d/su /etc/pam.d/gdm-password; do + [ -f "$f" ] && sed -ri '/pam_motd\.so/d' "$f" +done + +rm -f /run/motd.dynamic +printf '%s\n' \ + 'session optional pam_motd.so motd=/run/motd.dynamic' \ + 'session optional pam_motd.so noupdate' \ + >> /etc/pam.d/login From a725d5fca7f81d4dea5bf4b55c8654c793d4bfeb Mon Sep 17 00:00:00 2001 From: Thomas Moore Date: Sun, 6 Sep 2026 13:32:26 +1200 Subject: [PATCH 18/18] Handle Ubuntu 26.04 sysctl configuration paths --- shared/templates/sysctl/ansible.template | 4 ++-- shared/templates/sysctl/bash.template | 2 +- shared/templates/sysctl/oval.template | 4 ++-- shared/templates/sysctl/sce-bash.template | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/shared/templates/sysctl/ansible.template b/shared/templates/sysctl/ansible.template index 76b97a10aaf0..213a81c8573d 100644 --- a/shared/templates/sysctl/ansible.template +++ b/shared/templates/sysctl/ansible.template @@ -22,7 +22,7 @@ - "/run/sysctl.d/" - "/usr/local/lib/sysctl.d/" {{% endif %}} -{{% if product not in ["fedora", "ol7", "ol8", "ol9", "rhcos4", "rhel8", "rhel9", "rhel10", "sle12", "sle15", "sle16", "slmicro5", "slmicro6", "ubuntu2204", "ubuntu2404"] %}} +{{% if product not in ["fedora", "ol7", "ol8", "ol9", "rhcos4", "rhel8", "rhel9", "rhel10", "sle12", "sle15", "sle16", "slmicro5", "slmicro6", "ubuntu2204", "ubuntu2404", "ubuntu2604"] %}} - "/usr/lib/sysctl.d/" {{% endif %}} @@ -54,7 +54,7 @@ loop: '{{ find_all_values.stdout_lines }}' when: find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines | length > find_correct_value.stdout_lines | length -{{% if product in [ "ubuntu2204", "ubuntu2404"] %}} +{{% if product in [ "ubuntu2204", "ubuntu2404", "ubuntu2604"] %}} - name: {{{ rule_title }}} - Comment out any occurrences of {{{ SYSCTLVAR }}} from /etc/ufw/sysctl.conf ansible.builtin.replace: path: "/etc/ufw/sysctl.conf" diff --git a/shared/templates/sysctl/bash.template b/shared/templates/sysctl/bash.template index fe6068fb8bd1..c1f40efb57b0 100644 --- a/shared/templates/sysctl/bash.template +++ b/shared/templates/sysctl/bash.template @@ -7,7 +7,7 @@ # Comment out any occurrences of {{{ SYSCTLVAR }}} from /etc/sysctl.d/*.conf files {{% if product in [ "sle12", "sle15", "slmicro5", "slmicro6"] %}} for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf /lib/sysctl.d/*.conf; do -{{% elif product in [ "ubuntu2204", "ubuntu2404"] %}} +{{% elif product in [ "ubuntu2204", "ubuntu2404", "ubuntu2604"] %}} for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf /etc/ufw/sysctl.conf; do {{% elif product not in [ "ol7", "ol8", "ol9", "rhcos4", "rhel8", "rhel9", "rhel10"] %}} for f in /etc/sysctl.d/*.conf /run/sysctl.d/*.conf /usr/local/lib/sysctl.d/*.conf /usr/lib/sysctl.d/*.conf; do diff --git a/shared/templates/sysctl/oval.template b/shared/templates/sysctl/oval.template index 916a62b97d9a..98ca932c003d 100644 --- a/shared/templates/sysctl/oval.template +++ b/shared/templates/sysctl/oval.template @@ -180,7 +180,7 @@ object_static_etc_sysctls_{{{ rule_id }}} -{{% if product not in [ "almalinux8", "almalinux9", "ol7", "ol8", "ol9", "rhcos4", "rhel8", "rhel9", "rhel10", "ubuntu2204", "ubuntu2404"] %}} +{{% if product not in [ "almalinux8", "almalinux9", "ol7", "ol8", "ol9", "rhcos4", "rhel8", "rhel9", "rhel10", "ubuntu2204", "ubuntu2404", "ubuntu2604"] %}} object_static_lib_sysctld_{{{ rule_id }}} {{% endif %}} @@ -231,7 +231,7 @@ ^.*\.conf$ {{{ sysctl_match() }}} -{{% if product not in [ "ol7", "ol8", "ol9", "rhcos4", "ubuntu2204", "ubuntu2404"] or 'rhel' in product or 'almalinux' in product %}} +{{% if product not in [ "ol7", "ol8", "ol9", "rhcos4", "ubuntu2204", "ubuntu2404", "ubuntu2604"] or 'rhel' in product or 'almalinux' in product %}} /lib/sysctl.d ^.*\.conf$ diff --git a/shared/templates/sysctl/sce-bash.template b/shared/templates/sysctl/sce-bash.template index 72fa4ff8289c..ca625c59afb2 100644 --- a/shared/templates/sysctl/sce-bash.template +++ b/shared/templates/sysctl/sce-bash.template @@ -4,13 +4,13 @@ # check-export = sysctl_{{{ SYSCTLID }}}_value=sysctl_{{{ SYSCTLID }}}_value {{% endif %}} -{{% if product in [ "ol7", "ol8", "ol9", "rhcos4", "rhel8", "rhel9", "rhel10", "ubuntu2204", "ubuntu2404"] %}} +{{% if product in [ "ol7", "ol8", "ol9", "rhcos4", "rhel8", "rhel9", "rhel10", "ubuntu2204", "ubuntu2404", "ubuntu2604"] %}} FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") {{% else %}} FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/lib/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") {{% endif %}} FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") -{{% if product in [ "ubuntu2204", "ubuntu2404"] %}} +{{% if product in [ "ubuntu2204", "ubuntu2404", "ubuntu2604"] %}} FILES_NOT_MANAGED_BY_PACKAGES+=("/etc/ufw/sysctl.conf") {{% endif %}}